Tutorials

Learn More

Consider two components operating at two different paces. The producer component is operating faster than the consumer component. So, FIFO is required to store transactions so that the consumer component can operate independently. 

The TLM FIFO provides storage for the transactions between two independently running processes. We have seen put and get methods to operate with only one outstanding transaction at a time i.e it is allowed to send the transaction Only after consumption of the previously sent transaction, in this case, the sender and receiver must be in sync else lead to blocking in one of the components. What if the case where the sender needs not wait for the receiver acknowledgment, it just wants to store it in memory and the receiver can consume it whenever required. Thus, sender and receiver needs not to be in sync. TLM FIFO makes it possible.

As we have seen in blocking methods, producers need to wait for acknowledgment from the consumer to send the next item. What if the producer is not a testbench component? Consider an example where DUT is sent information packets through some protocol and TB can take more time to operate on that packet. So, there can be chances that DUT can send multiple packets in the meantime. TLM FIFO stores such incoming transaction from DUT and testbench can operate independently.

Types of TLM FIFO

  1. uvm_tlm_fifo
  2. uvm_tlm_analysis_fifo

uvm_tlm_fifo

In TLM FIFO,  producer pushes to FIFO from and consumer pop from FIFO are independent of each other.

Producer’s put_port has to connect to TLM FIFO’s put_export and consumer’s get_port has to connect to TLM FIFO’s get_export. Connections to uvm_tlm_fifo establish at a higher hierarchical level (Ex. at env class) during the connect_phase.

uvm_tlm_fifo Methods

Methods

Description

new

To create TLM FIFO.

function new (string        name, 

              uvm_component parent=null, 

              int           size=1

             );

Size – Represents the size of TLM FIFO.

If a size is 0 then TLM FIFO is not bounded.

size

Returns the size of TLM FIFO.

If a size is 0 then TLM FIFO is not bounded.

used

Return number of entries put into TLM FIFO.

is_empty

No entries in TLM FIFO returns 1 else returns 0

is_full

on  TLM FIFO full, returns 1 else returns 0.

Full condition: FIFO size == number of entries in FIFO.

flush

On calling, it removes all entries from TLM FIFO

Thus, on calling used method, it returns 0  (<tlm_fifo>.used returns 0)

On calling is_empty method, it returns 1 (<tlm_fifo>,is_empty return 1)

uvm_tlm_fifo Example

TLM FIFO block diagram
`include "uvm_macros.svh"
import uvm_pkg::*;

`include "seq_item.sv"

class producer extends uvm_component;
  seq_item req;
  uvm_blocking_put_port #(seq_item) tlm_put;
  
  `uvm_component_utils(producer)
  
  function new(string name = "producer", uvm_component parent = null);
    super.new(name, parent);
    tlm_put = new("tlm_put", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    
    repeat(10) begin
      req = seq_item::type_id::create("req");
      assert(req.randomize());
      tlm_put.put(req);
      `uvm_info(get_name(), $sformatf("Send value = %0h", req.value), UVM_NONE);
      #5;
    end
  endtask
endclass

class consumer extends uvm_component;
  seq_item req;
  uvm_blocking_get_port #(seq_item) tlm_get;
  
  `uvm_component_utils(consumer)
  
  function new(string name = "consumer", uvm_component parent = null);
    super.new(name, parent);
    tlm_get = new("tlm_get", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    
    repeat(10) begin
      #10;
      tlm_get.get(req);
      `uvm_info(get_name(), $sformatf("Received value = %0h", req.value), UVM_NONE);
    end
  endtask
endclass

class env extends uvm_env;
  uvm_tlm_fifo #(seq_item) tlm_fifo;
  producer pro;
  consumer con;
  `uvm_component_utils(env)
  
  function new(string name = "env", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    tlm_fifo = new("tlm_fifo", this, 3);
    pro = producer::type_id::create("pro", this);
    con = consumer::type_id::create("con", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    pro.tlm_put.connect(tlm_fifo.put_export);
    con.tlm_get.connect(tlm_fifo.get_export);
  endfunction
endclass
              
class test extends uvm_test;
  env env_o;
  `uvm_component_utils(test)
  
  function new(string name = "test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env_o = env::type_id::create("env_o", this);
  endfunction
 
  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    
    fork begin
      while(1) begin
        if(env_o.tlm_fifo.is_empty) `uvm_info(get_name(), "UVM_TLM_FIFO is empty", UVM_LOW);
        if(env_o.tlm_fifo.is_full) `uvm_info(get_name(), "UVM_TLM_FIFO is full", UVM_LOW);
        `uvm_info(get_name(), $sformatf("UVM_TLM_FIFO size = %0d, used = %0d", env_o.tlm_fifo.size(), env_o.tlm_fifo.used()), UVM_LOW);
        #5;
      end
    end
    begin
      #30;
      if(env_o.tlm_fifo.is_full) begin
        `uvm_info(get_name(), $sformatf("Before flush: UVM_TLM_FIFO used = %0d, is_empty = %0d", env_o.tlm_fifo.used, env_o.tlm_fifo.is_empty), UVM_LOW);
        env_o.tlm_fifo.flush();
        `uvm_info(get_name(), $sformatf("After flush: UVM_TLM_FIFO used = %0d, is_empty = %0d", env_o.tlm_fifo.used, env_o.tlm_fifo.is_empty), UVM_LOW);
      end
    end
    join_any
    disable fork;
    phase.drop_objection(this);
  endtask
endclass

module tb_top;
  initial begin
    run_test("test");
  end
endmodule

Output:

UVM_INFO testbench.sv(95) @ 0: uvm_test_top [uvm_test_top] UVM_TLM_FIFO is empty
UVM_INFO testbench.sv(97) @ 0: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 0
UVM_INFO testbench.sv(24) @ 0: uvm_test_top.env_o.pro [pro] Send value = 5
UVM_INFO testbench.sv(97) @ 5: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 1
UVM_INFO testbench.sv(24) @ 5: uvm_test_top.env_o.pro [pro] Send value = 8
UVM_INFO testbench.sv(47) @ 10: uvm_test_top.env_o.con [con] Received value = 5
UVM_INFO testbench.sv(97) @ 10: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 1
UVM_INFO testbench.sv(24) @ 10: uvm_test_top.env_o.pro [pro] Send value = 2
UVM_INFO testbench.sv(97) @ 15: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 2
UVM_INFO testbench.sv(24) @ 15: uvm_test_top.env_o.pro [pro] Send value = 6
UVM_INFO testbench.sv(47) @ 20: uvm_test_top.env_o.con [con] Received value = 8
UVM_INFO testbench.sv(97) @ 20: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 2
UVM_INFO testbench.sv(24) @ 20: uvm_test_top.env_o.pro [pro] Send value = b
UVM_INFO testbench.sv(96) @ 25: uvm_test_top [uvm_test_top] UVM_TLM_FIFO is full
UVM_INFO testbench.sv(97) @ 25: uvm_test_top [uvm_test_top] UVM_TLM_FIFO size = 3, used = 3
UVM_INFO testbench.sv(104) @ 30: uvm_test_top [uvm_test_top] Before flush: UVM_TLM_FIFO used = 3, is_empty = 0
UVM_INFO testbench.sv(106) @ 30: uvm_test_top [uvm_test_top] After flush: UVM_TLM_FIFO used = 0, is_empty = 1
UVM_INFO testbench.sv(24) @ 30: uvm_test_top.env_o.pro [pro] Send value = a

Peek interface example(uvm_put_port and uvm_peek_port using uvm_tlm_fifo)

`include "uvm_macros.svh"
import uvm_pkg::*;

class seq_item extends uvm_sequence_item;
  rand bit [3:0] value;
  `uvm_object_utils(seq_item)
  
  function new(string name = "seq_item");
    super.new(name);
  endfunction
endclass

class producer extends uvm_component;
  uvm_put_port#(seq_item) tlm_put;
  seq_item req;
  `uvm_component_utils(producer)
  
  function new(string name = "producer", uvm_component parent = null);
    super.new(name, parent);
    tlm_put = new("tlm_put", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    
    req = seq_item::type_id::create("req");
    assert(req.randomize());
    tlm_put.put(req);
    `uvm_info(get_type_name(), $sformatf("Send value = %0h", req.value), UVM_NONE);
  endtask
endclass

class consumer extends uvm_component;
  seq_item req;
  uvm_peek_port #(seq_item) tlm_peek;
   
  `uvm_component_utils(consumer)
  
  function new(string name = "consumer", uvm_component parent = null);
    super.new(name, parent);
    tlm_peek = new("tlm_peek", this);
  endfunction
  
  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    
    if(tlm_peek.can_peek) begin
      tlm_peek.peek(req);
      `uvm_info(get_type_name(), $sformatf("Peek1: Received value = %0h", req.value), UVM_NONE);
      tlm_peek.peek(req); // Will get same value as entry is not removed.
      `uvm_info(get_type_name(), $sformatf("Peek2: Received value = %0h", req.value), UVM_NONE);
    end
    else
      `uvm_info(get_type_name(), "can_peek failed",UVM_NONE);
  endtask
endclass

class env extends uvm_env;
  producer pro;
  consumer con;
  uvm_tlm_fifo #(seq_item) tlm_fifo;
  `uvm_component_utils(env)
  
  function new(string name = "env", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    tlm_fifo = new("tlm_fifo", this, 2);
    pro = producer::type_id::create("pro", this);
    con = consumer::type_id::create("con", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    pro.tlm_put.connect(tlm_fifo.put_export);
    con.tlm_peek.connect(tlm_fifo.peek_export);
  endfunction
endclass
              
class test extends uvm_test;
  env env_o;
  `uvm_component_utils(test)
  
  function new(string name = "test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env_o = env::type_id::create("env_o", this);
  endfunction
 
  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    #50;
    phase.drop_objection(this);
  endtask
endclass

module tb_top;
  initial begin
    run_test("test");
  end
endmodule

Output:

UVM_INFO testbench.sv(29) @ 0: uvm_test_top.env_o.pro [producer] Send value = 0
UVM_INFO testbench.sv(49) @ 0: uvm_test_top.env_o.con [consumer] Peek1: Received value = 0
UVM_INFO testbench.sv(51) @ 0: uvm_test_top.env_o.con [consumer] Peek2: Received value = 0