We have seen the scenario in TLM - Put, where data sent to componentB is executed using the put() method defined in B. Let us consider the case where there are two components A and C connected to B's export. Then, any data object sent by either componentA or componentC will be received by componentB and operated upon by the same put() method. If there's a need to be able to process them separately, you would need to have two separate put() methods.

componentA and componentC connected to same export

UVM provides us with the `uvm_*_put_imp_decl () macro to deal with cases when the component needs to provide two put implementation ports.


`uvm_put_imp_decl (_1)
`uvm_put_imp_decl (_2)

class my_put_imp #(type T=int) extends uvm_component;
	uvm_put_imp_1 #(T, my_put_imp #(T)) put_imp1;
	uvm_put_imp_2 #(T, my_put_imp #(T)) put_imp2;
	
	function void put_1 (input T t);
		// puts coming from put_imp1
	endfunction
	
	function void put_2 (input T t);
		// puts coming from put_imp2
	endfunction
	...
endclass

Note the following from the sample code above:

  • `uvm_put_imp_decl should be outside the class
  • uvm_put_imp class used inside my_put_imp should have the argument passed to the macro appended to it.
  • put() function/task should also have the argument appended to it.

UVM will create two new classes by the name uvm_put_imp_1 and uvm_put_imp_2 when the macros are called. That is the reason why you have to append the argument to uvm_put_imp when trying to create an object. Even the put() method defined in those classes have the argument appended to it. You may give any name as the argument instead of _1 and _2, but make sure to use the same afterwards.

compA and compC connected to separate ports on compB

Example

Let's first create componentA and componentC.


//------------------------ componentA -------------------------------------

	class componentA extends uvm_component;
   `uvm_component_utils (componentA)

   // We are creating a put_port parameterized to use a "simple_packet" type of data
   uvm_blocking_put_port #(simple_packet) put_port;
   simple_packet  pkt;

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

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Remember that put_port is a class object and it will have to be 
      // created with new ()
      put_port = new ("put_port", this);
   endfunction

   virtual task run_phase (uvm_phase phase);
      // Let us generate 5 packets and send it via the put_port
      repeat (2) begin
         pkt = simple_packet::type_id::create ("pkt");
         assert(pkt.randomize ()); 
         `uvm_info ("COMPA", "Packet sent to CompB", UVM_LOW)
         pkt.print (uvm_default_line_printer);
         put_port.put (pkt);
      end
   endtask
endclass

//------------------------ componentC -------------------------------------
class componentC extends uvm_component;
   `uvm_component_utils (componentC)

   // We are creating a put_port which will accept a "simple_packet" type of data
   uvm_blocking_put_port #(simple_packet) put_port;
   simple_packet  pkt;

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

   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Remember that put_port is a class object and it will have to be 
      // created with new ()
      put_port = new ("put_port", this);
   endfunction

   virtual task run_phase (uvm_phase phase);
      // Let us generate 5 packets and send it via the put_port
      repeat (2) begin
         pkt = simple_packet::type_id::create ("pkt");
         assert(pkt.randomize ()); 
         `uvm_info ("COMPC", "Packet sent to CompB", UVM_LOW)
         pkt.print (uvm_default_line_printer);
         put_port.put (pkt);
      end
   endtask
endclass

Coming to componentB, notice that we have used the sample code shown before to implement the macros.


`uvm_blocking_put_imp_decl (_1)
`uvm_blocking_put_imp_decl (_2)

class componentB extends uvm_component;
   `uvm_component_utils (componentB)
   
   // Mention type of transaction, and type of class that implements the put ()
   uvm_blocking_put_imp_1 #(simple_packet, componentB) put_imp1;
   uvm_blocking_put_imp_2 #(simple_packet, componentB) put_imp2;

   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);
      put_imp1 = new ("put_imp1", this);
      put_imp2 = new ("put_imp2", this);
   endfunction

   task put_1 (simple_packet pkt);
      `uvm_info ("COMPB", "Packet received from put_1", UVM_LOW)
      pkt.print (uvm_default_line_printer);
   endtask

   task put_2 (simple_packet pkt);
      `uvm_info ("COMPB", "Packet received from put_2", UVM_LOW)
      pkt.print (uvm_default_line_printer);
   endtask
endclass

Environment will have all the three component instantiations, and connect componentA with componentB's put_imp1 port, while componentC will be connected to componentB's put_imp2.


class my_env extends uvm_env;
   `uvm_component_utils (my_env)

   componentA compA;
   componentC compC;
   componentB compB;

   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);
      compA = componentA::type_id::create ("compA", this);
      compC = componentC::type_id::create ("compC", this);
      compB = componentB::type_id::create ("compB", this);
   endfunction

   virtual function void connect_phase (uvm_phase phase);
      compA.put_port.connect (compB.put_imp1);  
      compC.put_port.connect (compB.put_imp2);
   endfunction
endclass
 Simulation Log
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   -     @2808
    compB       componentB              -     @2759
      put_imp1  uvm_blocking_put_imp_1  -     @2861
      put_imp2  uvm_blocking_put_imp_2  -     @2910
    compC       componentC              -     @2729
      put_port  uvm_blocking_put_port   -     @2962
---------------------------------------------------

UVM_INFO ./tb/tlm.sv(95) @ 0: uvm_test_top.m_top_env.compC [COMPC] Packet sent to CompB
pkt: (simple_packet@3032) { addr: 'h53  data: 'hc4  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(144) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from put_2
pkt: (simple_packet@3032) { addr: 'h53  data: 'hc4  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(95) @ 0: uvm_test_top.m_top_env.compC [COMPC] Packet sent to CompB
pkt: (simple_packet@3051) { addr: 'h40  data: 'h3f  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(144) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from put_2
pkt: (simple_packet@3051) { addr: 'h40  data: 'h3f  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3014) { addr: 'h2f  data: 'h64  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(139) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from put_1
pkt: (simple_packet@3014) { addr: 'h2f  data: 'h64  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(61) @ 0: uvm_test_top.m_top_env.compA [COMPA] Packet sent to CompB
pkt: (simple_packet@3061) { addr: 'hb8  data: 'h27  rwb: 'h0  }
UVM_INFO ./tb/tlm.sv(139) @ 0: uvm_test_top.m_top_env.compB [COMPB] Packet received from put_1
pkt: (simple_packet@3061) { addr: 'hb8  data: 'h27  rwb: 'h0  }

--- UVM Report catcher Summary ---