大多數(shù)UVM測試平臺由可重復(fù)使用的驗(yàn)證組件組成,除非我們正在對像MIPI-CSI這樣的簡單協(xié)議進(jìn)行塊級驗(yàn)證。考慮驗(yàn)證簡單協(xié)議的場景;在這種情況下,我們可以忍受只有一個(gè)音序器將刺激發(fā)送給驅(qū)動器。頂級測試將使用此序列器來處理序列(如上一篇博客文章中所述)。在這里,我們可能不需要虛擬序列(或虛擬序列器)。
但是,當(dāng)我們嘗試將此IP集成到我們的SOC(或頂級塊)中時(shí),我們肯定要考慮重用用于驗(yàn)證這些塊的測試平臺組件。讓我們考慮一個(gè)簡單的案例,其中我們正在集成兩個(gè)這樣的塊:兩個(gè)音序器驅(qū)動這兩個(gè)塊。從頂級測試來看,我們需要一種方法來控制這兩個(gè)音序器。
這可以通過使用虛擬序列器和虛擬序列來實(shí)現(xiàn)。另一種方法是通過將序列器傳遞給啟動方法,從頂級測試顯式調(diào)用序列的啟動方法。
我將通過一個(gè)例子來解釋這種用法,其中 USB 主機(jī)集成在 AXI 環(huán)境中。讓我們看看如何從頂級測試中控制USB音序器和AXI音序器。對于此特定測試,我想配置 AXI 寄存器,然后發(fā)送 USB 傳輸。對于配置 AXI 寄存器,我使用序列說axi_cfg_reg_sequence,對于發(fā)送 USB 傳輸,我使用我在上一篇博客文章中使用的序列 (usb_complex_sequence)。下面是一個(gè)示例,其中在不使用虛擬序列的情況下控制多個(gè)序列器。
//Top-level test where multiple sequencers are controlled from the //phase method. class axi_cfg_usb_bulk_test extends uvm_test; `uvm_component_utils(usb_ltssm_bulk_test) //Sequences which needs to be exercised usb_reset_sequence u_reset_seq; axi_reset_sequence a_reset_seq; usb_complex_sequence u_bulk_seq; axi_cfg_reg_sequence a_cfg_reg_seq; function new (strint name=”axi_cfg_usb_bulk_test”, uvm_component parent=null); … endfunction: new //Call the reset sequences in the reset_phase virtual task reset_phase (uvm_phase phase); phase.raise_objections(this); … //Executing sequences by calling the start method directly by passing the //corresponding sequencer a_reset_seq.start(env.axi_master_agent_obj.sequencer); u_reset_seq.start(env.usb_host_agent_obj.sequencer); … phase.drop_objections(this); endtask:reset_phase virtual task main_phase (uvm_phase phase); phase.raise_objections(this); … //Executing sequences by calling the start method directly by passing the //corresponding sequencer a_cfg_reg_seq.start(env.axi_master_agent_obj.sequencer); u_bulk_seq.start(env.usb_host_agent_obj.sequencer); … phase.drop_objections(this); endtask:main_phase endclass: axi_cfg_usb_bulk_test
這不是控制序列器的最有效方法,因?yàn)槲覀冎苯釉跍y試中使用簡單的序列并使其變得復(fù)雜。通過這樣做,我們無法進(jìn)一步重用這些復(fù)雜的場景來開發(fā)更復(fù)雜的場景。相反,如果我們嘗試創(chuàng)建一個(gè)序列并在測試中使用該序列,那么我們也可以在其他測試(或序列)中重用這些序列。此外,與在頂級測試中創(chuàng)建整個(gè)方案相比,維護(hù)和調(diào)試這些序列將更容易。
在理解了為什么我們需要虛擬序列和虛擬序列器之后,讓我們看看如何通過上面顯示的相同示例來實(shí)現(xiàn)這一點(diǎn)。
我們需要做的第一件事是創(chuàng)建一個(gè)虛擬序列器。請注意,虛擬序列只能與虛擬序列器關(guān)聯(lián)(但不能與非虛擬序列器關(guān)聯(lián))。虛擬排序器也像任何其他非虛擬排序器一樣派生自uvm_sequencer,但不附加到任何驅(qū)動程序。虛擬音序器引用了我們嘗試控制的音序器。這些引用從頂部環(huán)境分配給非虛擬序列器。
//Virtual sequencer having references to non-virtual sequencers
Class system_virtual_sequencer extends uvm_sequencer;
//References to non-virtual sequencer
usb_sequencer usb_seqr;
axi_sequencer axi_seqr;
function new (string name=”usb_ltssm_bulk_test”,
uvm_component parent=null);
…
endfunction: new
`uvm_component_utils(system_virtual_sequencer)
endclass: system_virtual_sequencer
//Top level environment, where virtual sequencer’s references
//are connected to non-virtual sequencers
class system_env extends uvm_env;
//Agents where the non-virtual sequencers are present
usb_host_agent usb_host_agent_obj;
axi_master_agent axi_master_agent_obj;
//Virtual sequencer
system_virtual_sequencer sys_vir_seqr;
`uvm_component_utils(system_env)
function new (string name=”system_env”, uvm_component parent=null);
…
endfunction: new
function void connect_phase(uvm_phase phase);
//Assigning the virtual sequencer’s references to non-virtual sequencers
sys_vir_seqr.usb_seqr = usb_host_agent_obj.sequencer;
sys_vir_seqr.axi_seqr = axi_master_agent_obj.sequencer;
endfunction: connect_phase
endclass: system_virtual_sequencer
現(xiàn)在我們有虛擬序列器,其中包含對非虛擬序列器的引用,我們想要控制這些序列,讓我們看看如何使用虛擬序列控制這些非虛擬序列器。
虛擬序列與任何其他序列相同,但與非虛擬序列不同,它與虛擬序列器相關(guān)聯(lián),因此它需要指示它必須使用哪個(gè)非虛擬序列來執(zhí)行基礎(chǔ)序列。另請注意,虛擬序列只能執(zhí)行序列或其他虛擬序列,而不能執(zhí)行項(xiàng)目。使用“uvm_do_on/”uvm_do_on_with執(zhí)行非虛擬序列,使用“uvm_do/”uvm_do_with執(zhí)行其他虛擬序列。
//virtual sequence for reset operation
class axi_usb_reset_virtual_sequence extends uvm_sequence;
`uvm_object_utils(axi_usb_reset_virtual_sequence)
//non-virtual reset sequences
usb_reset_sequence u_reset_seq;
axi_reset_sequence a_reset_seq;
function new (string name=” axi_usb_reset_virtual_sequence”,
uvm_component parent=null);
…
endfunction: new
…
task body();
…
//executingnon-virtual sequence on the corresponding
//non-virtual sequencer using `uvm_do_on
`uvm_do_on(a_reset_seq, p_sequencer.axi_seqr)
a_reset_seq.get_response();
`uvm_do_on(u_reset_seq, p_sequencer.usb_seqr)
u_reset_seq.get_response();
endtask: body
endclass: axi_usb_reset_virtual_sequence
//virtual sequence for doing axi register configuration
//followed by USB transfer
class axi_cfg_usb_bulk_virtual_sequence extends uvm_sequence;
`uvm_object_utils(axi_cfg_usb_bulk_virtual_sequence)
`uvm_declare_p_sequencer(system_virtual_sequencer)
//Re-using the non-virtual sequences
usb_complex_sequence u_bulk_seq;
axi_cfg_reg_sequence a_cfg_reg_seq;
function new (string name=” axi_cfg_usb_bulk_virtual_sequence”,
uvm_component parent=null);
…
endfunction: new
task body();
…
//executingnon-virtual sequence on the corresponding
//non-virtual sequencer using `uvm_do_on
`uvm_do_on(a_cfg_reg_seq, p_sequencer.axi_seqr)
a_cfg_req_seq.get_response();
`uvm_do_on(u_bulk_seq, p_sequencer.usb_seqr)
u_bulk_seq.get_response();
endtask: body
endclass: axi_cfg_usb_bulk_virtual_sequence
在上面的虛擬序列中,我們執(zhí)行axi_cfg_reg_sequence然后執(zhí)行usb_complex_sequence。現(xiàn)在虛擬序列和虛擬序列器已經(jīng)準(zhǔn)備就緒,讓我們看看如何從頂級測試中執(zhí)行此虛擬序列。
//virtual sequence for reset operation
class axi_usb_reset_virtual_sequence extends uvm_sequence;
`uvm_object_utils(axi_usb_reset_virtual_sequence)
//non-virtual reset sequences
usb_reset_sequence u_reset_seq;
axi_reset_sequence a_reset_seq;
function new (string name=” axi_usb_reset_virtual_sequence”,
uvm_component parent=null);
…
endfunction: new
…
task body();
…
//executingnon-virtual sequence on the corresponding
//non-virtual sequencer using `uvm_do_on
`uvm_do_on(a_reset_seq, p_sequencer.axi_seqr)
a_reset_seq.get_response();
`uvm_do_on(u_reset_seq, p_sequencer.usb_seqr)
u_reset_seq.get_response();
endtask: body
endclass: axi_usb_reset_virtual_sequence
//virtual sequence for doing axi register configuration
//followed by USB transfer
class axi_cfg_usb_bulk_virtual_sequence extends uvm_sequence;
`uvm_object_utils(axi_cfg_usb_bulk_virtual_sequence)
`uvm_declare_p_sequencer(system_virtual_sequencer)
//Re-using the non-virtual sequences
usb_complex_sequence u_bulk_seq;
axi_cfg_reg_sequence a_cfg_reg_seq;
function new (string name=” axi_cfg_usb_bulk_virtual_sequence”,
uvm_component parent=null);
…
endfunction: new
task body();
…
//executingnon-virtual sequence on the corresponding
//non-virtual sequencer using `uvm_do_on
`uvm_do_on(a_cfg_reg_seq, p_sequencer.axi_seqr)
a_cfg_req_seq.get_response();
`uvm_do_on(u_bulk_seq, p_sequencer.usb_seqr)
u_bulk_seq.get_response();
endtask: body
endclass: axi_cfg_usb_bulk_virtual_sequence
到目前為止,我們了解為什么以及如何使用虛擬序列。在使用虛擬序列和虛擬序列器時(shí),我們還應(yīng)該記住一些事情,以節(jié)省大量的調(diào)試時(shí)間。
1. 在配置序列中的變量(使用虛擬序列執(zhí)行)時(shí),我們必須使用通過虛擬序列的路徑。在上面的示例中,使用非虛擬序列器路徑在較低級別的序列中設(shè)置變量將不起作用。
uvm_config_db#(int unsigned)::set(this,“env.usb_host_agent_obj.sequencer.u_bulk_sequence”,“sequence_length”,10);
即使u_bulk_sequence在 usb_host_agent_obj.sequencer 上運(yùn)行,這也不起作用,因?yàn)榇诵蛄惺怯商摂M序列創(chuàng)建的,因此分層路徑應(yīng)來自虛擬序列,但不使用非虛擬序列器。因此,設(shè)置變量的正確方法是使用虛擬序列路徑。
uvm_config_db#(int unsigned)::set(this,“env.sys_vir_seqr.axi_cfg_usb_bulk_virtual_sequence.u_bulk_sequence”,“sequence_length”,10);
對于工廠覆蓋也是如此。例如,由于上述原因相同,下面的工廠覆蓋將不起作用。
set_inst_override_by_type(“env.usb_host_agent_obj.*”,usb_transfer_item::get_type(), cust_usb_transfer_item::get_type());
在上面的示例中,我們嘗試使用頂級測試中的新派生類型更改基礎(chǔ)序列項(xiàng)。為此,我們需要使用虛擬序列器路徑。
set_inst_override_by_type(“env.sys_vir_seqr.*”,usb_transfer_item::get_type(), cust_usb_transfer_item::get_type());
經(jīng)驗(yàn)法則是:
? 如果序列是由虛擬序列直接或間接創(chuàng)建的,則工廠覆蓋或配置中的任何分層路徑都應(yīng)使用虛擬序列器的分層路徑。
? 如果序列是由非虛擬序列創(chuàng)建的,則工廠覆蓋或配置中的任何分層路徑都應(yīng)使用非虛擬序列器的分層路徑。
2. 即使我們有虛擬序列器來控制多個(gè)序列器,在某些測試中,我們可能只需要一個(gè)序列器(例如單獨(dú)的 USB 序列器)。在這種情況下,我們必須直接使用非虛擬序列器的分層路徑(而不是虛擬序列器的引用路徑)來配置變量或工廠覆蓋。使用虛擬序列器的引用路徑將不起作用,因?yàn)榉翘摂M序列器的層次結(jié)構(gòu)不正確。
uvm_config_db#(uvm_object_wrapper)::set(this, “env.sys_vir_seqr.usb_seqr.main_phase”, “default_sequence”, usb_complex_sequence::type_id::get());
上述配置將不起作用,因?yàn)榉翘摂M序列器 (usb_seqr/usb_host_agent_obj.sequencer) 實(shí)際上是在代理中創(chuàng)建的,因此此排序器的父級是代理,而不是虛擬序列器,盡管引用在虛擬序列器中。因此,在嘗試在實(shí)際序列器中設(shè)置變量時(shí),我們不應(yīng)使用虛擬序列器路徑,而是必須使用通過代理的分層路徑(序列器的實(shí)際父級)。
uvm_config_db#(uvm_object_wrapper)::set(this, “env.usb_host_agent_obj.sequencer.main_phase”, “default_sequence”, usb_complex_sequence::type_id::get());
3. 每當(dāng)我們使用虛擬音序器并希望從虛擬音序器控制非虛擬音序器時(shí),請確保將所有實(shí)際音序器中的default_sequence設(shè)置為 null。
uvm_config_db#(uvm_object_wrapper)::set(this, “env.usb_host_agent_obj.sequencer.main_phase”, “default_sequence”, null);
uvm_config_db#(uvm_object_wrapper)::set(this, “env.axi_master_agent_obj.sequencer.main_phase”, “default_sequence”, null);
這很重要,因?yàn)槿绻腥魏蝑efault_sequence集,那么我們的非虛擬序列器將同時(shí)運(yùn)行虛擬序列中的default_sequence和序列。要僅從虛擬序列器控制非虛擬序列器,我們需要將非虛擬序列器的default_sequence設(shè)置為 null。
我希望您發(fā)現(xiàn)這篇文章有助于理解虛擬序列并通過概述的指南節(jié)省調(diào)試時(shí)間。我相信在使用虛擬序列時(shí)會還有其他準(zhǔn)則,我們學(xué)習(xí)調(diào)試復(fù)雜環(huán)境的更難的方法;請與我分享任何此類準(zhǔn)則。
審核編輯:郭婷
-
UVM
+關(guān)注
關(guān)注
0文章
183瀏覽量
20012 -
MIPI
+關(guān)注
關(guān)注
11文章
355瀏覽量
50878 -
音序器
+關(guān)注
關(guān)注
0文章
30瀏覽量
4149
發(fā)布評論請先 登錄
UVM序列的創(chuàng)建和運(yùn)行及中斷服務(wù)程序?qū)崿F(xiàn)方案
數(shù)字IC驗(yàn)證之“什么是UVM”“UVM的特點(diǎn)”“UVM提供哪些資源”(2)連載中...
什么是uvm?uvm的特點(diǎn)有哪些呢
請問一下在UVM中的UVMsequences是什么意思啊
如何構(gòu)建UVM寄存器模型并將寄存器模型集成到驗(yàn)證環(huán)境中
談?wù)?b class='flag-5'>UVM中的uvm_info打印
UVM中seq.start()和default_sequence執(zhí)行順序
UVM中的可重用序列
UVM中uvm_config_db機(jī)制背后的大功臣
如何用Verdi查看UVM環(huán)境中的變量?
UVM中uvm_config_db機(jī)制背后的大功臣
一文詳解UVM設(shè)計(jì)模式
UVM設(shè)計(jì)中的sequence啟動方式有哪幾種呢?
UVM中的虛擬序列:為什么,如何?
評論