UVM中Driver,transaction,sequence,sequencer之間的關系。
UVM將原來在Driver中的數據定義部分,單獨拿出來成為Transaction,主要完成數據的randomize and constrained.
在Transaction之上有增加一層sequence,它可以調用,控制同一類型的transaction。
在UVM中增減component名叫sequencer,來留下與sequence的接口,並控制sequence的啟動,定義與UVM環境中其他的component的
聯系。
uvm_sequence_base從uvm_sequence_item繼承而來,uvm_sequence_item從uvm_transaction繼承而來,uvm_transaction從
uvm_object繼承而來。
一個sequence的啟動有兩種方式:
1)將sequence設置為某個sequencer的某個phase的default_sequence。這樣隨着phase的執行,sequence會自動執行。
uvm_config_db #(uvm_object_wrapper)::set(this, "env.i_agent.sqr.main_phase", "default_sequence",
case0_sequence::type_id::get() );
2)可以在任何component的task phase中直接調用start函數。
my_seq.start(sequencer); //一般在testcase的相應phase中啟動一個sequence。
//virtual sequence/sequencer的嵌套使用,sequence中包含幾個sequencer,
//在這個sequence的body中,再啟動其他的sequence
第二種方式,主要用在需要對不同的sequence的執行進行控制,或並行執行的時候。
uvm_sequence_base中定義有一個uvm_phase類型的starting_phase的變量,一般用在sequence的body中設置objection。
當選擇使用default_sequence的方式來啟動時,這個變量會被自動設置。當選擇第二種方式來啟動時,這個變量需要自己設置,保證不為空。
sequence啟動后,開始執行內部定義的一個task——virtual task body(); 一般定義為virtual類型,方便重載。
還有兩個回調函數pre_body(); post_body();來供用戶配置。
其中在task body()中,定義的函數有:`uvm_create(m_trans)等價於m_trans=new("m_trans");
sequencer.wait_for_grant(prior);依靠指定的優先級向sequencer發出請求。
this.pre_do();執行完后,將會對transation進行隨機化。
this.mid_do(); 這三個do函數為callback函數。
sequencer.send_request();
sequencer.wait_for_item_done();
this.post_do();
這些是UVM內部定義的一個task body內應該有的幾個部分,但是一般可以直接new+自己的randomized+`uvm_send來完成。
wait_for_grant和pre_do又可以組成一個start_item的宏,剩下四部分還能組成finish_item的宏。整個還可以組成uvm_do系列的宏。還可以
增加很多priority的選項。
sequence作為一個object,可以在任何component上進行例化/create,再調用start啟動sequence。
同一個sequencer上:
同一個sequencer上可以同時啟動多個sequence,這時sequencer通過sequence/transaction的優先級進行調用。
在sequence中,可以通過lock,來使得該sequencer在執行完當前隊列中的sequence后,在單獨的執行接下來的sequence。直到unlock函數。
grab則表示不等隊列中的sequence執行完,在當前sequence執行完之后,sequencer便單獨的執行接下來的sequence,
直到ungrab,然后再執行隊列中的sequence。
重載is_relevant() function可以讓sequence主動放棄sequencer的使用權。
重載wait_for_relevant(),通過修改環境中的變量,可以使得sequence重新有效。
在每個sequence中,都有一個uvm_sequencer_base類型的變量,稱為m_sequencer,當需要在sequence和sequencer之間傳遞值時,可以通過
$cast(x_sequencer, m_sequencer),然后通過x_sequencer直接調用sequencer中的值。
uvm中通過宏定義`uvm_declare_p_sequencer(my_sequencer)進行了封裝。之后可以使用p_sequencer
而sequencer可以通過config_db與其他的component交換配置。
通過virtual_sequence和virtual_sequencer來進行控制:
1)定義virtual sequence---不指定transaction,內部的body task直接通過sequence.start(不同sequencer)開始不同sequencer的sequence。
2)定義virtual sequencer--不指定uvm_sequence_item,內部包含多個具體針對不同transaction的sequencer
3)將virtual sequencer中的sequencer在connect_phase中,連接到具體的agent上的sequencer。
4)通過啟動virtual sequencer上的sequencer,進而啟動agent上的sequencer。
5)agent上的sequencer通過export與driver上的port連接。
推薦在virtual sequence上的控制objection。
sequence的task函數內部還可以再啟動其他的sequence,但是必須是同一transaction類型的。但是virtual sequence可以啟動其他不相同
的sequence。所以在實際的使用中,常在virtual sequencer指定default_virtual_sequence,再在其中調用需要在這個phase執行的
sequence,從而達到控制sequence的目的。
sequencer中的兩個變量:
m_sequencer是uvm_sequencer_base類型的的對象。定義在sequence類內部,作為一些操作的default_sequencer。
p_sequencer相當於是m_seqencer經過$cast()處理的。是啟動該sequence的那個sequencer類型的對象。可以調用更高一級的
sequencer內的新變量。UVM內部使用宏定義`uvm_declare_psequencer(my_sequencer)來聲明。
sequence中的宏'uvm_send本質上是start_item和finish_item兩個宏組合而成一體來的。'uvm_send不會完成
sequence的new和randomized