前文展示了使用本质为阻塞性质的uvm_blocking_get_port
TLM端口的示例,其中接收方会停滞等待发送方完成get
任务。
类似地,UVM TLM还提供非阻塞类型的uvm_nonblocking_get_port
,发送方需通过try_get
来检测get
是否成功,或通过can_get
方法判断发送方是否已准备好启动传输。与之前相同,UVM TLM非阻塞get端口最终应连接到非阻塞get实现端口。
UVM TLM Nonblocking Get Example
下面定义了一个名为Packet
的类,作为将在组件之间传输的数据项。该类的对象将包含两个随机变量,这些变量可以在发送前进行随机化处理。
// 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_endfunction new(string name = "Packet");super.new(name);endfunction
endclass
1. Create receiver class with a port of type uvm_nonblocking_get_port
创建了一个名为componentB
的类,其中实例化了一个参数化的uvm_nonblocking_get_port
端口,用于接收Packet
类型的数据对象。该端口最好在该组件的build_phase
阶段通过new()
方法进行实例化。
在本示例中,通过调用try_get
方法从get_port
句柄接收Packet
类型的类对象。通过由可配置变量控制的简单循环,可以接收多个此类数据包。理想情况下,当传输成功时try_get
函数应返回1,失败时返回0,该功能应由实现该函数的发送方提供。
class componentB extends uvm_component;`uvm_component_utils (componentB)// Create a get_port to request for data from componentAuvm_nonblocking_get_port #(Packet) m_get_port;int m_num_tx = 2;function new (string name, uvm_component parent);super.new (name, parent);endfunctionvirtual function void build_phase (uvm_phase phase);super.build_phase (phase);m_get_port = new ("m_get_port", this);endfunctionvirtual 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 functionrepeat (m_num_tx) beginif (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);endphase.drop_objection(this);endtask
endclass
3. Create sender class that implements the get
method
发送方类需要使用uvm_nonblocking_get_imp
定义一个实现端口。由于该端口本质上是非阻塞的,try_get
实现必须由该组件定义为函数。
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);endfunctionvirtual function void build_phase (uvm_phase phase);super.build_phase (phase);m_get_imp = new ("m_get_imp", this);endfunctionvirtual 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;endfunctionvirtual function bit can_get();endfunction
endclass
4. Connect port and its implementation at a higher level
端口与其实现之间的连接必须在更高的层次结构中进行。由于在这个示例中,两个组件都直接实例化在测试类中,它们之间的连接可以在测试的connect_phase
阶段完成。如果这两个组件实例化在另一个组件或环境中,则必须在该组件或环境的connect_phase
阶段进行连接。
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 transfersvirtual 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 herevirtual function void connect_phase (uvm_phase phase);compB.m_get_port.connect (compA.m_get_imp);endfunctionvirtual 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 - @1836compA componentA - @1905m_get_imp uvm_nonblocking_get_imp - @1971compB componentB - @1936m_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
接收方可以先通过can_get
函数查询发送方是否已准备就绪,而不是直接尝试获取数据包,然后再获取数据包。
class componentB extends uvm_component;`uvm_component_utils (componentB)// Create a get_port to request for data from componentAuvm_nonblocking_get_port #(Packet) m_get_port;int m_num_tx = 2;function new (string name, uvm_component parent);super.new (name, parent);endfunctionvirtual function void build_phase (uvm_phase phase);super.build_phase (phase);m_get_port = new ("m_get_port", this);endfunctionvirtual 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 functionrepeat (m_num_tx) beginwhile (!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);endphase.drop_objection(this);endtask
endclass
在此示例中,componentA
中的 can_get
函数被设置为返回随机值,以模拟接收方的准备状态。
class componentA extends uvm_component;`uvm_component_utils (componentA)uvm_nonblocking_get_imp #(Packet, componentA) m_get_imp;// Rest of the code remains samevirtual 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;endfunctionvirtual 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 - @1837compA componentA - @1906m_get_imp uvm_nonblocking_get_imp - @1972compB componentB - @1937m_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 ---