前文展示了使用本質為阻塞性質的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 ---