提高UVM Sequences 復(fù)用程度的3大準則
[導(dǎo)讀]就我個人而言,我覺得編寫sequence是在驗證任何IP時最具挑戰(zhàn)性的部分。首先需要仔細構(gòu)想場景,然后coding。如果沒有任何程度的復(fù)用,我們需要從頭為每個場景編寫一個sequence,這使得sequence難以維護和調(diào)試。sequence的編寫和調(diào)試是非常體現(xiàn)驗證工程師編碼能...
就我個人而言,我覺得編寫sequence是在驗證任何IP時最具挑戰(zhàn)性的部分。首先需要仔細構(gòu)想場景,然后coding。如果沒有任何程度的復(fù)用,我們需要從頭為每個場景編寫一個sequence,這使得sequence難以維護和調(diào)試。
sequence的編寫和調(diào)試是非常體現(xiàn)驗證工程師編碼能力的地方之一,如果每一個sequnce都有著完全不同的工作模式,那么維護起來非常痛苦。
網(wǎng)絡(luò)上有一個段子,程序員最討厭4件事情:1、寫文檔2、別人不寫文檔3、寫注釋4、別人不寫注釋
想象一下,如果你驗證同事離職,交接給你上百個定向且詭異的測試用例或者sequence?你會不會立馬想去重構(gòu)。
sequences 由多個事務(wù)激勵組成,在UVM中其繼承自參數(shù)化類uvm_sequence。通過這些事務(wù)觸發(fā)一些驗證工程師希望觸及的場景,而sequence的分層會創(chuàng)建一些更加復(fù)雜的場景激勵。驗證空間隨著設(shè)計規(guī)模指數(shù)級上升,驗證激勵自然也會越來越復(fù)雜。
在上面的sequence 中,我們試圖將發(fā)送多次id為2的事務(wù),在uvm_test中將該sequence指定為default sequence即可。
到目前為止,sequence看起來既簡單又直接。但是直接的代碼往往意味著麻煩的堆疊。為了確保sequence在更復(fù)雜的場景中重用,我們必須遵循一些準則或者說代碼規(guī)范。
1、只在base sequence 類中的pre_start和post_start任務(wù)中raising objections和 dropping objections來管理測試用例的開始和結(jié)束。通過這種方式,能夠減少每一個sequence子類中的相關(guān)phase控制代碼。
需要注意的是,只有被定義為default sequence才會自動執(zhí)行starting_phase,否則就需要手動調(diào)用了。
2、使用UVM configurations 機制從測試用例中獲取值。在上面的示例中,沒有給出控制sequence的按鈕,一些都靠sequence自身的隨機,這對于擴展用例非常不友好。我們可以對sequence做如下的修改,以提供更加精確的激勵控制。
通過上述修改,我們對測試用例進行了控制,以配置device_id、sequence_length和type。這里需要注意的是:
3、在創(chuàng)建復(fù)雜sequence的時候盡量去復(fù)用簡單的sequence。例如,在下面的sequence 中順序發(fā)送不同的sequnce(層次化和模塊化,永遠是編碼規(guī)范之一):
sequence的編寫和調(diào)試是非常體現(xiàn)驗證工程師編碼能力的地方之一,如果每一個sequnce都有著完全不同的工作模式,那么維護起來非常痛苦。
網(wǎng)絡(luò)上有一個段子,程序員最討厭4件事情:1、寫文檔2、別人不寫文檔3、寫注釋4、別人不寫注釋
想象一下,如果你驗證同事離職,交接給你上百個定向且詭異的測試用例或者sequence?你會不會立馬想去重構(gòu)。
sequences 由多個事務(wù)激勵組成,在UVM中其繼承自參數(shù)化類uvm_sequence。通過這些事務(wù)觸發(fā)一些驗證工程師希望觸及的場景,而sequence的分層會創(chuàng)建一些更加復(fù)雜的場景激勵。驗證空間隨著設(shè)計規(guī)模指數(shù)級上升,驗證激勵自然也會越來越復(fù)雜。
class usb_simple_sequence extends uvm_sequence #(usb_transfer);rand int unsigned sequence_length;constraint reasonable_seq_len { sequence_length < 10 };//Constructorfunction new(string name=”usb_simple_bulk_sequence”);super.new(name);endfunction//Register with factory`uvm_object_utils(usb_simple_bulk_sequence)//the body() task is the actual logic of the sequencevirtual task body();repeat(sequence_length)`uvm_do_with(req, {//Setting the device_id to 2req.device_id == 8’d2;//Setting transfer type to BULKreq.type == usb_transfer::BULK_TRANSFER;})endtask : bodyendclass |
class usb_simple_bulk_test extends uvm_test;…virtual function void build_phase(uvm_phase phase );…uvm_config_db#(uvm_object_wrapper)::set(this, "sequencer_obj.main_phase","default_sequence", usb_simple_sequence::type_id::get());…endfunction : build_phaseendclass |
1、只在base sequence 類中的pre_start和post_start任務(wù)中raising objections和 dropping objections來管理測試用例的開始和結(jié)束。通過這種方式,能夠減少每一個sequence子類中的相關(guān)phase控制代碼。
task pre_start()if(starting_phase != null)starting_phase.raise_objection(this);endtask : pre_starttask post_start()if(starting_phase != null)starting_phase.drop_objection(this);endtask : post_start |
class usb_simple_bulk_test extends uvm_test;usb_simple_sequence seq;…virtual function void main_phase(uvm_phase phase );…//User need to set the starting_phase as sequence start methodis explicitly called to invoke the sequenceseq.starting_phase = phase;seq.start();…endfunction : main_phaseendclass |
class usb_simple_sequence extends uvm_sequence #(usb_transfer);rand int unsigned sequence_length;constraint reasonable_seq_len { sequence_length < 10 };…virtual task body();usb_transfer::type_enum local_type;bit[7:0] local_device_id;//Get the values for the variables in case toplevel//test/sequence sets it.uvm_config_db#(int unsigned)::get(null, get_full_name(),“sequence_length”, sequence_length);uvm_config_db#(usb_transfer::type_enum)::get(null,get_full_name(), “l(fā)ocal_type”, local_type);uvm_config_db#(bit[7:0])::get(null, get_full_name(),?“l(fā)ocal_device_id”, local_device_id);repeat(sequence_length)`uvm_do_with(req, {req.device_id == local_device_id;req.type == local_type;})endtask : bodyendclass |
uvm_config_db#()::set中使用的參數(shù)類型和字符串(第三個參數(shù))應(yīng)該與uvm_config_db#()::get中使用的類型相匹配,否則將無法正確配置。這個地方如果出錯會非常痛苦,但好在不需要經(jīng)常修改,痛苦一次就好。另外,這幾個配置項是隨機類型,相應(yīng)的配置值也需要滿足約束范圍。3、在創(chuàng)建復(fù)雜sequence的時候盡量去復(fù)用簡單的sequence。例如,在下面的sequence 中順序發(fā)送不同的sequnce(層次化和模塊化,永遠是編碼規(guī)范之一):
class usb_complex_sequence extends uvm_sequence #(usb_transfer);//Object of simple sequence used for sending bulk transferusb_simple_sequence simp_seq_bulk;//Object of simple sequence used for sending interrupt transferusb_simple_sequence simp_seq_int;…virtual task body();//Variable for getting device_id for bulk transferbit[7:0] local_device_id_bulk;//Variable for getting device_id for interrupt transferbit[7:0] local_device_id_int;//Variable for getting sequence length for bulkint unsigned local_seq_len_bulk;//Variable for getting sequence length for interruptint unsigned local_seq_len_int;//Get the values for the variables in case top level//test/sequence sets it.uvm_config_db#(int unsigned)::get(null, get_full_name(),“l(fā)ocal_seq_len_bulk”,local_seq_len_bulk);uvm_config_db#(int unsigned)::get(null, get_full_name(),“l(fā)ocal_seq_len_int”,local_seq_len_int);uvm_config_db#(bit[7:0])::get(null, get_full_name(),“l(fā)ocal_device_id_bulk”,local_device_id_bulk);uvm_config_db#(bit[7:0])::get(null, get_full_name(),“l(fā)ocal_device_id_int”,local_device_id_int);//Set the values for the variables to the lowerlevel//sequence/sequence item, which we got from//above uvm_config_db::get.//Setting the values for bulk sequenceuvm_config_db#(int unsigned)::set(null, {get_full_name(),”.”,”simp_seq_bulk”}, “sequence_length”,local_seq_len_bulk);uvm_config_db#(usb_transfer::type_enum)::set(null, {get_full_name(),“.”,“simp_seq_bulk”} , “l(fā)ocal_type”,usb_transfer::BULK_TRANSFER);uvm_config_db#(bit[7:0])::set(null, {get_full_name(), “.”,”simp_seq_bulk”}, “l(fā)ocal_device_id”,local_device_id_bulk);//Setting the values for interrupt sequenceuvm_config_db#(int unsigned)::set(null, {get_full_name(),”.”,”simp_seq_int”}, “sequence_length”,local_ seq_len_int);uvm_config_db#(usb_transfer::type_enum)::set(null, {get_full_name(),“.”,“simp_seq_int”} , “l(fā)ocal_type”,usb_transfer::INT_TRANSFER);uvm_config_db#(bit[7:0])::set(null,{get_full_name(),“.”,”simp_seq_bulk”},“l(fā)ocal_device_id”,local_device_id_int);`uvm_do(simp_seq_bulk)simp_seq_bulk.get_response();`uvm_send(simp_seq_int)simp_seq_int.get_response();endtask : bodyendclass |





