TLM FIFO
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
- uvm_tlm_fifo
- 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
`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
TLM Tutorials