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.

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 classuvm_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.

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
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 ---