This UVM TLM example uses put
ports, TLM FIFOs and get
ports discussed in previous articles to build a testbench that has TLM ports at different levels.

TLM FIFO can be extended to have another component called componentB to accept packets using another internal FIFO and sub-component.
A class called Packet is defined below to act as the data item that will be transferred from one component to another. This class object will have two random variables that can be randomized before sending.
class Packet extends uvm_object;
rand bit[7:0] addr;
rand bit[7:0] data;
`uvm_object_utils_begin(Packet)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "Packet");
super.new(name);
endfunction
endclass
subComp1
This component is exactly the same as in UVM TLM FIFO example and starts sending packets using its uvm_blocking_put_port
.
class subComp1 extends uvm_component;
`uvm_component_utils (subComp1)
// Create a blocking TLM put port which can send an object
// of type 'Packet'
uvm_blocking_put_port #(Packet) m_put_port;
int m_num_tx;
function new (string name = "subComp1", uvm_component parent= null);
super.new (name, parent);
endfunction
// Remember that TLM put_port is a class object and it will have to be
// created with new ()
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_put_port = new ("m_put_port", this);
endfunction
// Create a packet, randomize it and send it through the port
// Note that put() is a method defined by the receiving component
// Repeat these steps N times to send N packets
virtual task run_phase (uvm_phase phase);
repeat (m_num_tx) begin
Packet pkt = Packet::type_id::create ("pkt");
assert(pkt.randomize ());
#50;
// Print the packet to be displayed in log
`uvm_info ("SUBCOMP1", "Packet sent to compA:tlm_fifo", UVM_LOW)
pkt.print (uvm_default_line_printer);
// Call the TLM put() method of put_port class and pass packet as argument
m_put_port.put (pkt);
end
endtask
endclass
subComp2
This sub-component is slightly slower in receiving packets compared to the one seen above, and accepts data through uvm_blocking_get_port
.
Note that this also has another put port of type uvm_blocking_put_port
to forward data out of componentA.
class subComp2 extends uvm_component;
`uvm_component_utils (subComp2)
// Create a get_port to request for data from subComp1
uvm_blocking_get_port #(Packet) m_get_port;
uvm_blocking_put_port #(Packet) m_put_port;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_get_port = new ("m_get_port", this);
m_put_port = new ("m_put_port", this);
endfunction
virtual task run_phase (uvm_phase phase);
Packet pkt;
forever begin
#100;
m_get_port.get (pkt);
`uvm_info ("SUBCOMP2", "Packet received from compA:tlm_fifo, forward it", UVM_LOW)
pkt.print (uvm_default_line_printer);
m_put_port.put(pkt);
end
endtask
endclass
ComponentA
This layer contains both sub-components connected together by a TLM FIFO since their transfer rates are different.
Note that it also has another put port of type uvm_blocking_put_port
to forward the packet it receives from subComp2 which is at a lower layer.
class componentA extends uvm_component;
`uvm_component_utils (componentA)
function new(string name="componentA", uvm_component parent=null);
super.new(name, parent);
endfunction
subComp1 m_subcomp_1;
subComp2 m_subcomp_2;
uvm_tlm_fifo #(Packet) m_tlm_fifo;
uvm_blocking_put_port #(Packet) m_put_port;
int m_num_tx;
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
// Create an object of both components
m_subcomp_1 = subComp1::type_id::create ("m_subcomp_1", this);
m_subcomp_2 = subComp2::type_id::create ("m_subcomp_2", this);
// Create a FIFO with depth 2
m_tlm_fifo = new ("uvm_tlm_fifo", this, 2);
m_put_port = new ("m_put_port", this);
m_subcomp_1.m_num_tx = m_num_tx;
endfunction
// Make componentA connections
virtual function void connect_phase (uvm_phase phase);
// Connect put port from subComp1 to TLM FIFO and then
// connect get_export of TLM FIFO with subComp2
m_subcomp_1.m_put_port.connect(m_tlm_fifo.put_export);
m_subcomp_2.m_get_port.connect(m_tlm_fifo.get_export);
// Now connect subComp2 to componentA for forwarding pkt
m_subcomp_2.m_put_port.connect(this.m_put_port);
endfunction
// Display a message when the FIFO is full
virtual task run_phase (uvm_phase phase);
forever begin
#10 if (m_tlm_fifo.is_full ())
`uvm_info ("COMPA", "componentA:TLM_Fifo is now FULL !", UVM_MEDIUM)
end
endtask
endclass
subComp3
Assume the destination component is even slower than the other components seen above and accepts packet using a uvm_blocking_get_port
.
// subComp3 accepts packet even slower than what componentA is sending out
// which is the reason we need a TLM FIFO in componentB
class subComp3 extends uvm_component;
`uvm_component_utils (subComp3)
// Create a get_port to request for data from subComp1
uvm_blocking_get_port #(Packet) m_get_port;
int m_num_tx;
function new (string name, uvm_component parent);
super.new (name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
m_get_port = new ("m_get_port", this);
endfunction
virtual task run_phase (uvm_phase phase);
Packet pkt;
repeat(m_num_tx) begin
#200;
m_get_port.get (pkt);
`uvm_info ("SUBCOMP3", "Packet received from componentA", UVM_LOW)
pkt.print (uvm_default_line_printer);
end
endtask
endclass
ComponentB
Another UVM TLM FIFO is required to be connected to subComp3 to buffer packets it receives because of the slower rate of destination. Note that this has a top level put_export port of type uvm_blocking_put_export
.
class componentB extends uvm_component;
`uvm_component_utils (componentB)
subComp3 m_subcomp_3;
uvm_tlm_fifo #(Packet) m_tlm_fifo;
uvm_blocking_put_export #(Packet) m_put_export;
int m_num_tx;
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);
// Create an object of both components
m_subcomp_3 = subComp3::type_id::create ("m_subcomp_3", this);
// Create a FIFO with depth 2
m_tlm_fifo = new ("tlm_fifo", this, 2);
// Create the export to connect with componentA
m_put_export = new ("m_put_export", this);
m_subcomp_3.m_num_tx = m_num_tx;
endfunction
virtual function void connect_phase (uvm_phase phase);
// Connect from componentB export to FIFO export
m_put_export.connect (m_tlm_fifo.put_export);
// Connect from FIFO export to subComponent3 port
m_subcomp_3.m_get_port.connect (m_tlm_fifo.get_export);
endfunction
// Display a message when the FIFO is full
virtual task run_phase (uvm_phase phase);
forever begin
#10 if (m_tlm_fifo.is_full ())
`uvm_info ("COMPB", "componentB:TLM_Fifo is now FULL !", UVM_MEDIUM)
end
endtask
endclass
Top Env/Test
The connection between a port and its implementation has to be done at a higher hierarchical level. Since both components are instantiated directly within the test class in this example, the connection between them can be done during the connect_phase
of the test. If these two components were instantiated in another component or environment, they have to be connected during the connect_phase
of that component or environment.
class my_test extends uvm_env;
`uvm_component_utils (my_test)
componentA compA;
componentB compB;
int m_num_tx;
function new (string name = "my_test", 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("componentA", this);
compB = componentB::type_id::create("componentB", this);
std::randomize(m_num_tx) with { m_num_tx inside {[4:10]}; };
`uvm_info("TEST", $sformatf("Create %0d packets in total", m_num_tx), UVM_LOW)
compA.m_num_tx = m_num_tx;
compB.m_num_tx = m_num_tx;
endfunction
// Connect the ports to the export of FIFO.
virtual function void connect_phase (uvm_phase phase);
compA.m_put_port.connect(compB.m_put_export);
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
// Let all components finish for purpose of illustration
phase.raise_objection(this);
#1000;
phase.drop_objection(this);
endtask
endclass
UVM_INFO @ 0: reporter [RNTST] Running test my_test... UVM_INFO testbench.sv(220) @ 0: uvm_test_top [TEST] Create 4 packets in total UVM_INFO testbench.sv(48) @ 50: uvm_test_top.componentA.m_subcomp_1 [SUBCOMP1] Packet sent to compA:tlm_fifo pkt: (Packet@2663) { addr: 'h1f data: 'h31 } UVM_INFO testbench.sv(79) @ 100: uvm_test_top.componentA.m_subcomp_2 [SUBCOMP2] Packet received from compA:tlm_fifo, forward it pkt: (Packet@2663) { addr: 'h1f data: 'h31 } UVM_INFO testbench.sv(48) @ 100: uvm_test_top.componentA.m_subcomp_1 [SUBCOMP1] Packet sent to compA:tlm_fifo pkt: (Packet@2685) { addr: 'hf4 data: 'h91 } UVM_INFO testbench.sv(48) @ 150: uvm_test_top.componentA.m_subcomp_1 [SUBCOMP1] Packet sent to compA:tlm_fifo pkt: (Packet@2699) { addr: 'hab data: 'ha8 } UVM_INFO testbench.sv(126) @ 150: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 160: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 170: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 180: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 190: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(154) @ 200: uvm_test_top.componentB.m_subcomp_3 [SUBCOMP3] Packet received from componentA pkt: (Packet@2663) { addr: 'h1f data: 'h31 } UVM_INFO testbench.sv(79) @ 200: uvm_test_top.componentA.m_subcomp_2 [SUBCOMP2] Packet received from compA:tlm_fifo, forward it pkt: (Packet@2685) { addr: 'hf4 data: 'h91 } UVM_INFO testbench.sv(48) @ 200: uvm_test_top.componentA.m_subcomp_1 [SUBCOMP1] Packet sent to compA:tlm_fifo pkt: (Packet@2681) { addr: 'h77 data: 'he7 } UVM_INFO testbench.sv(126) @ 200: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 210: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 220: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 230: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 240: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 250: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 260: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 270: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 280: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(126) @ 290: uvm_test_top.componentA [COMPA] componentA:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(79) @ 300: uvm_test_top.componentA.m_subcomp_2 [SUBCOMP2] Packet received from compA:tlm_fifo, forward it pkt: (Packet@2699) { addr: 'hab data: 'ha8 } UVM_INFO testbench.sv(198) @ 300: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 310: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 320: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 330: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 340: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 350: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 360: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 370: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 380: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 390: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(154) @ 400: uvm_test_top.componentB.m_subcomp_3 [SUBCOMP3] Packet received from componentA pkt: (Packet@2685) { addr: 'hf4 data: 'h91 } UVM_INFO testbench.sv(79) @ 400: uvm_test_top.componentA.m_subcomp_2 [SUBCOMP2] Packet received from compA:tlm_fifo, forward it pkt: (Packet@2681) { addr: 'h77 data: 'he7 } UVM_INFO testbench.sv(198) @ 400: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 410: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 420: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 430: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 440: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 450: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 460: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 470: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 480: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 490: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 500: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 510: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 520: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 530: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 540: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 550: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 560: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 570: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 580: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(198) @ 590: uvm_test_top.componentB [COMPB] componentB:TLM_Fifo is now FULL ! UVM_INFO testbench.sv(154) @ 600: uvm_test_top.componentB.m_subcomp_3 [SUBCOMP3] Packet received from componentA pkt: (Packet@2699) { addr: 'hab data: 'ha8 } UVM_INFO testbench.sv(154) @ 800: uvm_test_top.componentB.m_subcomp_3 [SUBCOMP3] Packet received from componentA pkt: (Packet@2681) { addr: 'h77 data: 'he7 } UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 1000: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 1000: reporter [UVM/REPORT/SERVER] --- UVM Report Summary ---