示例:
具体概念详见[UVM 事务级建模TLM 单向/多向通信 端口 FIFO通信](https://blog.csdn.net/qq_40456702/article/details/126682331?spm=1001.2014.3001.5501)
component A 每隔 50ns 往 tlm_fifo 写入一个 transaction,component B 每隔 100ns 从 tlm_fifo 读出一个 transaction
1. 定义 transaction
// Packet (transaction)继承自uvm_object,其在组件之间传输
class Packet extends uvm_object;
randbit[7:0] addr;
randbit[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
2. 定义 component A
// 创建component A,定义 put_port,实现 transaction 的生成、约束和发送
class componentA extendsuvm_component;
`uvm_component_utils (componentA)
uvm_blocking_put_port #(Packet) m_put_port;
int m_num_tx = 2;
function new (string name = "componentA", uvm_component parent= null);
super.new (name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_put_port = new ("m_put_port", this);
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
repeat (m_num_tx) begin // component A每隔 50个时钟周期, 往 tlm_fifo 写入一个 transaction,写两次。
Packet pkt = Packet::type_id::create ("pkt");
assert(pkt.randomize ());
#50;
//Print the packet to be displayed in log
`uvm_info ("COMPA", "Packetsent to CompB", 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
phase.drop_objection(this);
endtask
endclass
3. 定义 component B
// 创建component B,定义get_port,实现transaction的接收
// 可以看出,uvm_tlm_fifo的两端都是export,都是put()和get()的实现端,而不是发起端
class componentB extendsuvm_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 // component B 每隔 100个时钟周期 从 tlm_fifo 读出一个 transaction,写两次
#100;
m_get_port.get(pkt);
`uvm_info ("COMPB", "ComponentAjust gave me the packet", UVM_LOW)
pkt.print (uvm_default_line_printer);
end
phase.drop_objection(this);
endtask
endclass
4. 在上层 env 定义 uvm_tlm_fifo
// 在更高的测试平台层次中定义uvm_tlm_fifo
// 连接 comp A 的 put_port 和 tlm_fifo 的 put_export,以及 comp B 的 get_port 和 tlm_fifo 的 get_export
class my_test extendsuvm_env;
`uvm_component_utils (my_test)
componentA compA;
componentB compB;
int m_num_tx;
//Create the UVM TLM Fifo that can accept simple_packet
uvm_tlm_fifo #(Packet) m_tlm_fifo;
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);
//Create an object of both components
compA = componentA::type_id::create ("compA", this);
compB = componentB::type_id::create ("compB", this);
std::randomize(m_num_tx) with {m_num_tx inside {[4:10]}; };
compA.m_num_tx = m_num_tx;
compB.m_num_tx = m_num_tx;
// 创建tlm fifo 深度为2
m_tlm_fifo = new ("uvm_tlm_fifo", this, 2);
endfunction
//Connect the ports to the export of FIFO.
virtual function void connect_phase(uvm_phase phase);
compA.m_put_port.connect(m_tlm_fifo.put_export);
compB.m_get_port.connect(m_tlm_fifo.get_export);
endfunction
// 查询fifo是否为满
virtual task run_phase(uvm_phase phase);
forever begin
#10;
if(m_tlm_fifo.is_full ())
`uvm_info ("UVM_TLM_FIFO", "Fifo isnow FULL !", UVM_MEDIUM)
end
endtask
endclass
仿真结果
# UVM_INFO tb_classes/componentA.sv(33) @50: uvm_test_top.compA [COMPA] Packet sent to CompB
# pkt: (Packet@543) { addr: 'h10 data: 'hcc }
# UVM_INFO tb_classes/componentB.sv(26) @100: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
# pkt: (Packet@543) { addr: 'h10 data: 'hcc }
# UVM_INFO tb_classes/componentA.sv(33) @100: uvm_test_top.compA [COMPA] Packet sent to CompB
# pkt: (Packet@544) { addr: 'h3e data: 'h92 }
# UVM_INFO tb_classes/componentA.sv(33) @150: uvm_test_top.compA [COMPA] Packet sent to CompB
# pkt: (Packet@545) { addr: 'hde data: 'h65 }
# UVM_INFO tb_classes/my_test.sv(40) @ 150:uvm_test_top [UVM_TLM_FIFO] Fifo is now FULL !
# UVM_INFO tb_classes/my_test.sv(40) @ 160:uvm_test_top [UVM_TLM_FIFO] Fifo is now FULL !
# UVM_INFO tb_classes/my_test.sv(40) @ 170:uvm_test_top [UVM_TLM_FIFO] Fifo is now FULL !
# UVM_INFO tb_classes/my_test.sv(40) @ 180:uvm_test_top [UVM_TLM_FIFO] Fifo is now FULL !
# UVM_INFO tb_classes/my_test.sv(40) @ 190:uvm_test_top [UVM_TLM_FIFO] Fifo is now FULL !
# UVM_INFO tb_classes/componentB.sv(26) @200: uvm_test_top.compB [COMPB] ComponentA just gave me the packet
# pkt: (Packet@544) { addr: 'h3e data: 'h92 }