A previous article showed examples of using a uvm_blocking_get_port TLM port that was blocking in nature where the receiver gets stalled until the sender finishes with the get task.

Similarly, UVM TLM also has a non-blocking method of type uvm_nonblocking_get_port where the sender has to use try_get to see if the get was successful or can_get method to see if the sender is ready to start a transfer. Like before, the UVM TLM non-blocking get port should ultimately be connected to a non-blocking get implementation port.

UVM TLM Nonblocking Get 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 receiver class with a port of type uvm_nonblocking_get_port

A class called componentB is created which has a uvm_nonblocking_get_port 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 received via the get_port handle by calling the try_get method. Many such packets can be received using a simple loop controlled by a configurable variable. The try_get function should ideally return 1 if the transfer was successful and 0 if it failed and should be provided by the sender which implements the function.


class componentB extends uvm_component;
   `uvm_component_utils (componentB)
 
   // Create a get_port to request for data from componentA
   uvm_nonblocking_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);
     
     // Try to get a transaction which does not consume simulation time
     // as try_get() is a function
     repeat (m_num_tx) begin
       if (m_get_port.try_get(pkt))
       	`uvm_info ("COMPB", "ComponentA just gave me the packet", UVM_LOW)
       else
         `uvm_info ("COMPB", "ComponentA did not give packet", UVM_LOW)
        pkt.print (uvm_default_line_printer);
      end
     phase.drop_objection(this);
   endtask
endclass
3. Create sender class that implements the get method

The sender class needs to define an implementation port using uvm_nonblocking_get_imp. Since the port is nonblocking in nature, the try_get implementation is a function which has to be defined by this component.


class componentA extends uvm_component;
   `uvm_component_utils (componentA)
 
   uvm_nonblocking_get_imp #(Packet, componentA) m_get_imp;
 
  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_imp = new ("m_get_imp", this);
   endfunction
 
   virtual function bit try_get (output Packet pkt);
      pkt = new();
      assert (pkt.randomize());
      `uvm_info ("COMPA", "ComponentB has requested for a packet", UVM_LOW)
      pkt.print (uvm_default_line_printer);
      return 1;
   endfunction
     
     virtual function bit can_get();
     endfunction
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_nonblocking_get_imp   -     @1971
  compB         componentB                -     @1936
    m_get_port  uvm_nonblocking_get_port  -     @2010
-----------------------------------------------------

UVM_INFO testbench.sv(97) @ 0: uvm_test_top.compA [COMPA] ComponentB has requested for a packet
Packet: (Packet@1903) { addr: 'he8  data: 'hc5  } 
UVM_INFO testbench.sv(67) @ 0: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@1903) { addr: 'he8  data: 'hc5  } 
UVM_INFO testbench.sv(97) @ 0: uvm_test_top.compA [COMPA] ComponentB has requested for a packet
Packet: (Packet@2058) { addr: 'hd6  data: 'hd  } 
UVM_INFO testbench.sv(67) @ 0: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
Packet: (Packet@2058) { addr: 'hd6  data: 'hd  } 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 0: 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) @ 0: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

UVM TLM can_get Example

Instead of directly trying to get a packet, the receiver can first query to see if the sender is ready or not with can_get function and then get the packet.


class componentB extends uvm_component;
   `uvm_component_utils (componentB)
 
   // Create a get_port to request for data from componentA
   uvm_nonblocking_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);
     
     // Try to get a transaction which does not consume simulation time
     // as try_get() is a function
     repeat (m_num_tx) begin
       while (!m_get_port.can_get()) begin
         #10 `uvm_info("COMPB", $sformatf("See if can_get() is ready"), UVM_LOW)
       end
       
       `uvm_info("COMPB", $sformatf("COMPA ready, get packet now"), UVM_LOW)
       m_get_port.try_get(pkt);
       pkt.print (uvm_default_line_printer);
      end
     phase.drop_objection(this);
   endtask
endclass

The can_get function in componentA is set to return a random value in this example to model readiness of the receiver.


class componentA extends uvm_component;
   `uvm_component_utils (componentA)
 
   uvm_nonblocking_get_imp #(Packet, componentA) m_get_imp;
 
  // Rest of the code remains same
 
   virtual function bit try_get (output Packet pkt);
      pkt = new();
      assert (pkt.randomize());
      `uvm_info ("COMPA", "ComponentB has requested for a packet", UVM_LOW)
      pkt.print (uvm_default_line_printer);
      return 1;
   endfunction
     
     virtual function bit can_get();
       bit ready;
       std::randomize(ready) with { ready dist {0:/70, 1:/30}; };
       return ready;
     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                   -     @1837
  compA         componentA                -     @1906
    m_get_imp   uvm_nonblocking_get_imp   -     @1972
  compB         componentB                -     @1937
    m_get_port  uvm_nonblocking_get_port  -     @2011
-----------------------------------------------------

UVM_INFO testbench.sv(60) @ 10: uvm_test_top.compB [COMPB] See if can_get() is ready
UVM_INFO testbench.sv(60) @ 20: uvm_test_top.compB [COMPB] See if can_get() is ready
UVM_INFO testbench.sv(60) @ 30: uvm_test_top.compB [COMPB] See if can_get() is ready
UVM_INFO testbench.sv(62) @ 30: uvm_test_top.compB [COMPB] COMPA ready, get packet now
UVM_INFO testbench.sv(97) @ 30: uvm_test_top.compA [COMPA] ComponentB has requested for a packet
Packet: (Packet@2065) { addr: 'h8c  data: 'h99  } 
Packet: (Packet@2065) { addr: 'h8c  data: 'h99  } 
UVM_INFO testbench.sv(62) @ 30: uvm_test_top.compB [COMPB] COMPA ready, get packet now
UVM_INFO testbench.sv(97) @ 30: uvm_test_top.compA [COMPA] ComponentB has requested for a packet
Packet: (Packet@2095) { addr: 'h97  data: 'hb8  } 
Packet: (Packet@2095) { addr: 'h97  data: 'hb8  } 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 30: 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) @ 30: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---