The put/get communication we have seen earlier typically require a corresponding export to supply the implementation. The idea behind having an analysis port is that a component like monitor should be able to generate a stream of transactions regardless of whether there is a target actually connected to it.

The uvm_analysis_port is a specialized TLM based class whose interface consists of a single function write () and can be embedded within any component as shown in the snippet below. This port contains a list of analysis exports that are connected to it. When the component (my_monitor) calls analysis_port.write(), it basically cycles through the list and calls the write() method of each connected export. If nothing is connected to it, then it simply does not do anything.


class my_monitor extends uvm_component;
	...
	uvm_analysis_port #(my_data) analysis_port;
	...
endclass

The advantage lies in the fact that an analysis port may be connected to zero, one or many analysis exports and allows a component to call write() method without depending on the number of connected exports. Also it's worth to note that write() is a void function and hence will always complete within the same simulation delta cycle.

Example

Let's take component B from the TLM Put example and connect three Subscribers to it. In order for component B to broadcast transactions to it's subscribers, there needs to be a special channel for communication. This is implemented by analysis ports. Analysis ports are declared using uvm_analysis_port so that component B can send transactions into the channel. We'll see how we can connect subscribers to this channel in a short while.

Declare analysis port


class componentB extends uvm_component;
	`uvm_component_utils (componentB)
   
	// Create an analysis port by the name "ap" that can broadcast packets of type "simple_packet"
	uvm_analysis_port #(simple_packet) ap;

	function new (string name = "componentB", uvm_component parent = null);
		super.new (name, parent);
	endfunction
   
	virtual function void build_phase (uvm_phase phase);
		super.build_phase (phase);
		ap = new ("analysis_port", this);
	endfunction

	virtual task run_phase (uvm_phase phase);
		super.run_phase (phase);
	  
		for (int i = 0; i < 5; i++) begin
	  		simple_packet pkt = simple_packet::type_id::create ("pkt");
	  		pkt.randomize();
       		// Now pass it to other components via the analysis port write() method
      		ap.write (pkt);
		end
	endtask
endclass

Define analysis port implementation

Now let us create the subscriber component parameterized to simple_packet data type. Note that the subscriber implements the write() method, and for our purpose, we can just display a message. Because we have derived our subscriber from uvm_subscriber, it already has an analysis port implementation object predefined by the name analysis_export. Hence we won't have to declare another implementation port for our purpose. See the snippet of uvm_subscriber class below.


virtual class uvm_subscriber #(type T=int) extends uvm_component;
	typedef uvm_subscriber #(T) this_type;
	
	uvm_analysis_imp #(T, this_type) analysis_export;
	
	pure virtual function void write (T t);
endclass

Note that analysis ports given by uvm_analysis_port are always connected to its implementation port declared using uvm_analysis_imp. Function write() is the place where you need to implement the operation required to be done on the incoming transaction. In this example, we are simply printing an acknowledgment statment.


class sub #(type T = simple_packet) extends uvm_subscriber #(T);
   `uvm_component_utils (sub)

   function new (string name = "sub", uvm_component parent = null);
      super.new (name, parent);
   endfunction

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
   endfunction

   // Note that the class object name has to be "t" - anything else will result
   // in compilation error
   virtual function void write (T t);
      `uvm_info (get_full_name(), "Sub got transaction", UVM_MEDIUM)
   endfunction
endclass
tlm-ap

Connect analysis port with its implementation

Since all our components are instantiated within the environment my_env, it is easier to connect between components at this level. This is done in the connect_phase() method where the analysis port of component B is connected with multiple implementation ports defined within each subscriber.


class my_env extends uvm_env;
   `uvm_component_utils (my_env)

   componentA  compA;
   componentB  compB;
   sub         sub1; 
   sub         sub2; 
   sub         sub3; 

   function new (string name = "my_env", uvm_component parent = null);
      super.new (name, parent);
   endfunction

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Create an object of both components
      compA = componentA::type_id::create ("compA", this);
      compB = componentB::type_id::create ("compB", this);
      sub1 = sub::type_id::create ("sub1", this);
      sub2 = sub::type_id::create ("sub2", this);
      sub3 = sub::type_id::create ("sub3", this);
   endfunction

   virtual function void connect_phase (uvm_phase phase);
      compA.put_port.connect (compB.put_export);  

      // Connect Analysis Ports
      compB.ap.connect (sub1.analysis_export);
      compB.ap.connect (sub2.analysis_export);
      compB.ap.connect (sub3.analysis_export);
   endfunction
endclass
 Simulation Log
----------------------------------------------------------------
CDNS-UVM-1.1d (15.10-s004)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
-------------------------------------------------------
Name                 Type                   Size  Value
-------------------------------------------------------
uvm_test_top         base_test              -     @2602
  m_top_env          my_env                 -     @2668
    compA            componentA             -     @2699
      put_port       uvm_blocking_put_port  -     @3015
    compB            componentB             -     @2729
      analysis_port  uvm_analysis_port      -     @3115
      put_export     uvm_blocking_put_imp   -     @3066
    sub1             sub                    -     @2759
      analysis_imp   uvm_analysis_imp       -     @2808
    sub2             sub                    -     @2839
      analysis_imp   uvm_analysis_imp       -     @2888
    sub3             sub                    -     @2869
      analysis_imp   uvm_analysis_imp       -     @2966
-------------------------------------------------------

UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3205) { addr: 'h2f  data: 'h64  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(91) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from CompA
----------------------------------
Name    Type           Size  Value
----------------------------------
pkt     simple_packet  -     @3205
  addr  integral       8     'h2f
  data  integral       8     'h64
  rwb   integral       1     'h0
----------------------------------
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub1 [uvm_test_top.m_top_env.sub1] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub2 [uvm_test_top.m_top_env.sub2] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub3 [uvm_test_top.m_top_env.sub3] Sub got transaction
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3198) { addr: 'hb8  data: 'h27  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(91) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from CompA
----------------------------------
Name    Type           Size  Value
----------------------------------
pkt     simple_packet  -     @3198
  addr  integral       8     'hb8
  data  integral       8     'h27
  rwb   integral       1     'h0
----------------------------------
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub1 [uvm_test_top.m_top_env.sub1] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub2 [uvm_test_top.m_top_env.sub2] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub3 [uvm_test_top.m_top_env.sub3] Sub got transaction
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3170) { addr: 'he3  data: 'h29  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(91) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from CompA
----------------------------------
Name    Type           Size  Value
----------------------------------
pkt     simple_packet  -     @3170
  addr  integral       8     'he3
  data  integral       8     'h29
  rwb   integral       1     'h0
----------------------------------
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub1 [uvm_test_top.m_top_env.sub1] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub2 [uvm_test_top.m_top_env.sub2] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub3 [uvm_test_top.m_top_env.sub3] Sub got transaction
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3175) { addr: 'h85  data: 'hbd  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(91) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from CompA
----------------------------------
Name    Type           Size  Value
----------------------------------
pkt     simple_packet  -     @3175
  addr  integral       8     'h85
  data  integral       8     'hbd
  rwb   integral       1     'h0
----------------------------------
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub1 [uvm_test_top.m_top_env.sub1] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub2 [uvm_test_top.m_top_env.sub2] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub3 [uvm_test_top.m_top_env.sub3] Sub got transaction
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3192) { addr: 'hdf  data: 'hab  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(91) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from CompA
----------------------------------
Name    Type           Size  Value
----------------------------------
pkt     simple_packet  -     @3192
  addr  integral       8     'hdf
  data  integral       8     'hab
  rwb   integral       1     'h0
----------------------------------
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub1 [uvm_test_top.m_top_env.sub1] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub2 [uvm_test_top.m_top_env.sub2] Sub got transaction
UVM_INFO ./tb/tlm.sv(122) @ 0: uvm_test_top.m_top_env.sub3 [uvm_test_top.m_top_env.sub3] Sub got transaction

--- UVM Report catcher Summary ---


Number of demoted UVM_FATAL reports  :    0
Number of demoted UVM_ERROR reports  :    0
Number of demoted UVM_WARNING reports:    0
Number of caught UVM_FATAL reports   :    0
Number of caught UVM_ERROR reports   :    0
Number of caught UVM_WARNING reports :    0

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :   27
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[COMPA]     5
[COMPB]     5
[RNTST]     1
[UVMTOP]     1
[uvm_test_top.m_top_env.sub1]     5
[uvm_test_top.m_top_env.sub2]     5
[uvm_test_top.m_top_env.sub3]     5
Simulation complete via $finish(1) at time 0 FS + 179