Any component can request to receive a transaction from another component through a TLM get port. The sending component should define an implementation of the get port. The implementation gives sender the chance to define what needs to be sent to the requestor. This is just the opposite of a put port seen in a previous article.

The port can be either blocking or nonblocking in nature, which will decide whether the get method will block execution in the receiver until the sender sends the object. The example shown below is a TLM blocking get port in one component connected to its implementation port in another component.

UVM TLM Get Port Example

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.


// Create a class data object that can be sent from one 
// component to another
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
1. Create sender class with a port of type uvm_blocking_get_imp

A class called componentA is created which has a uvm_blocking_get_imp parameterized to accept a data object of type Packet. The port has to be instantiated with the new() method preferably in the build_phase of the same component.

In this example, a class object of type Packet is created, randomized and sent via the implementation of get() method. Note that it has an ouput of type Packet . Many such packets can be sent using a simple loop controlled by a configurable variable.


class componentA extends uvm_component;
   `uvm_component_utils (componentA)
 
   // Create an export to send data to componentB
   uvm_blocking_get_imp #(Packet, componentA) m_get_imp;
   Packet  pkt;
 
  function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Remember that m_get_imp is a class object and it will have to be 
      // created with new ()
      m_get_imp = new ("m_get_imp", this);
   endfunction
 
   // This task will output a new packet 
   virtual task get (output Packet pkt);
      // Create a new packet
      pkt = new();
      assert (pkt.randomize());
      `uvm_info ("COMPA", "ComponentB has requested for a packet", UVM_LOW)
      pkt.print (uvm_default_line_printer);
   endtask
endclass
3. Create receiver class that waits on the get method

The receiver class needs to define a getport using uvm_blocking_get_port to receive the packet. Since the port is blocking in nature, the get method implementation is a task that was defined by the sender shown above.


class componentB extends uvm_component;
   `uvm_component_utils (componentB)
 
   // Create a get_port to request for data from componentA
   uvm_blocking_get_port #(Packet) m_get_port;
   int m_num_tx = 2;
 
  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;
     phase.raise_objection(this);
     repeat (m_num_tx) begin
         m_get_port.get (pkt);
         `uvm_info ("COMPB", "ComponentA just gave me the packet", UVM_LOW)
        pkt.print (uvm_default_line_printer);
      end
     phase.drop_objection(this);
   endtask
endclass
tlm-get 4. Connect port and its implementation at a higher level

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_test;
  `uvm_component_utils (my_test)
 
   componentA compA;
   componentB compB;
 
  function new (string name = "my_test", uvm_component parent = null);
      super.new (name, parent);
   endfunction
 
   // Create objects of both components, set number of transfers
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      compA = componentA::type_id::create ("compA", this);
      compB = componentB::type_id::create ("compB", this);
   endfunction
 
   // Connection between componentA and componentB is done here
   virtual function void connect_phase (uvm_phase phase);
     compB.m_get_port.connect (compA.m_get_imp);  
   endfunction
  
   virtual function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
    uvm_top.print_topology();
  endfunction
endclass
 Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_root.svh(579) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------
Name            Type                   Size  Value
--------------------------------------------------
uvm_test_top    my_test                -     @1836
  compA         componentA             -     @1905
    m_get_imp   uvm_blocking_get_imp   -     @1971
  compB         componentB             -     @1936
    put_export  uvm_blocking_get_port  -     @2010
--------------------------------------------------

UVM_INFO testbench.sv(86) @ 0: uvm_test_top.compA [COMPA] ComponentB has requested for a packet, give the following packet to componentB
Packet: (Packet@1877) { addr: 'hdd  data: 'hce  } 
UVM_INFO testbench.sv(54) @ 0: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@1877) { addr: 'hdd  data: 'hce  } 
UVM_INFO testbench.sv(86) @ 0: uvm_test_top.compA [COMPA] ComponentB has requested for a packet, give the following packet to componentB
Packet: (Packet@2058) { addr: 'h4b  data: 'hf5  } 
UVM_INFO testbench.sv(54) @ 0: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@2058) { addr: 'h4b  data: 'hf5  } 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

Get Port Blocking Behavior

The example shown above used a blocking get port declared of the type uvm_blocking_get_port which would stall the receiver from resuming until the get task returns. This blocking behavior can be observed if there is a delay inside the implementation of the get method within componentA or the sender. The code shown below inserts a 20ns delay inside the get task.


   virtual task get (output Packet pkt);
      // Create a new packet
      pkt = new();
      assert (pkt.randomize());
      
      // Lets assume componentA takes some time to prepare packet
     `uvm_info("COMPA", "Preparing packet ...", UVM_LOW)
     #20;
     `uvm_info("COMPA", "Preparing packet over ...", UVM_LOW)
      pkt.print (uvm_default_line_printer);
   endtask

Note that time is consumed by componentA inside get task which blocks the sender from sending the next packet. At 20ns, componentA finishes the task and proceeds to send the next packet.

 Simulation Log
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_root.svh(579) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------
Name            Type                   Size  Value
--------------------------------------------------
uvm_test_top    my_test                -     @1837
  compA         componentA             -     @1906
    m_get_imp   uvm_blocking_get_imp   -     @1972
  compB         componentB             -     @1937
    m_get_port  uvm_blocking_get_port  -     @2011
--------------------------------------------------

UVM_INFO testbench.sv(89) @ 0: uvm_test_top.compA [COMPA] Preparing packet ...
UVM_INFO testbench.sv(91) @ 20: uvm_test_top.compA [COMPA] Preparing packet over ...
Packet: (Packet@1904) { addr: 'he8  data: 'hc5  } 
UVM_INFO testbench.sv(55) @ 20: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@1904) { addr: 'he8  data: 'hc5  } 
UVM_INFO testbench.sv(89) @ 20: uvm_test_top.compA [COMPA] Preparing packet ...
UVM_INFO testbench.sv(91) @ 40: uvm_test_top.compA [COMPA] Preparing packet over ...
Packet: (Packet@2071) { addr: 'hd6  data: 'hd  } 
UVM_INFO testbench.sv(55) @ 40: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@2071) { addr: 'hd6  data: 'hd  } 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 40: 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) @ 40: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---