一、m_sequencer 1、什麼是m_sequencer m_sequencer是定義在uvm_sequencer_item中的,uvm_sequencer_base類型的句柄,也就是說 m_sequencer是uvm_sequencer_item的成員變數 m_sequencer是指向uvm_ ...
一、m_sequencer
1、什麼是m_sequencer
m_sequencer是定義在uvm_sequencer_item中的,uvm_sequencer_base類型的句柄,也就是說
- m_sequencer是uvm_sequencer_item的成員變數
- m_sequencer是指向uvm_sequencer_base的句柄
- 任何派生於uvm_sequencer_item的類都會擁有一個m_sequencer
m_sequencer源碼如下:
class uvm_sequence_item extends uvm_transaction;
...
protected uvm_sequencer_base m_sequencer;
...
endclass
m_sequencer在類庫中的關係如下圖紫色箭頭所示:
2、為什麼要有m_sequencer
sequence屬於object,sequencer屬於component。
正常來說,sequence無法與sequencer進行交互,也不可能通過component的結構層次獲得頂層配置及其他信息。因此需要一個能溝通sequence和sequencer的橋梁,m_sequencer就是這個橋梁。
3、怎麼使用m_sequencer
通常調用uvm_do系列巨集時,uvm能夠自動根據傳入的sequence或sequence_item調用對應的方法。使m_sequencer由指向uvm_sequencer_base,變為指向用戶指定的sequencer,(例如類庫中的your_sequencer),如下圖藍色虛線將變為紫色實線。
由此搭建了sequence和sequencer的橋梁,調用其他方法同理(不管是什麼方法,沒有改變m_sequencer指向給定的sequencer這一本質)。
因此使用者只需要調用所需方法,有關於m_sequencer的使用由uvm自動完成了。
值得註意的一點是用戶指定的sequencer是uvm_sequencer_base的子類,對於m_sequencer而言,此時是父類句柄指向了子類對象,這也為下麵的動態轉換打下了基礎。
二、p_sequencer
1、什麼是p_sequencer
p_sequencer是由`uvm_decalre_p_sequencer巨集,定義在用戶指定的sequence(例如類庫中的your_sequence)中的,用戶指定的類型的句柄(例如類庫中的your_sequencer),也就是說
- p_sequencer是由uvm_decalre_p_sequencer巨集產生的
- p_sequencer是用戶指定的sequence的成員變數(這裡是your_sequence的成員變數,因為`uvm_decalre_p_sequencer巨集是在your_sequence中使用的)
- p_sequencer是指向用戶指定的類型的句柄(這裡是your_sequencer的成員變數)
p_sequencer源代碼如下:
`define uvm_declare_p_sequencer(SEQUENCER)
SEQUENCER p_sequencer; //SEQUENCER是由用戶指定的類型
virtual function void m_set_p_sequencer();
super.m_set_p_sequencer(); //父類的m_set_p_sequencer是空函數
if (!$cast(p_sequencer, m_sequencer))
`uvm_fatal("DCLPSQ", $sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name()))
endfunction
可能到這裡還是有些抽象,接下來我們進行一個更為形象的說明。
2、為什麼需要p_sequencer
在sequence機制中,sequence就像是一個快遞,它可以裝入商品(sequence_itm),也可以裝入另一個快遞(sequence);sequencer就像是商家,他把快遞交給物流公司(driver),物流公司再把快遞交給用戶(DUT)。
當有很多個快遞時,物流公司怎麼知道把哪個快遞交給哪個用戶呢,這就需要商家給快遞上註明收貨人和發貨人的信息(your_sequencer中的dmac和smac等)。
也就是說your_sequence要訪問your_sequencer中的成員變數dmac和smac,雖然這是your_sequence中的m_sequencer經過調用`uvm_do後已經指向了your_sequencer,但此時他的類型還是uvm_sequencer_base,而uvm_sequencer_base是your_sequencer的父類。父類句柄直接訪問子類對象是不允許的。
因此我們需要將m_sequencer的類型轉換成子類類型(也就是your_sequencer)。
首先我們在your_sequencer中聲明瞭一個your_sequencer類型的句柄x_sequencer,再將m_sequencer動態轉換成子類句柄,這樣your_sequence就可以訪問your_sequencer的成員變數了。
代碼如下:
class your_sequence extends uvm_sequence #(your_transaction);
your_trasaction your_trans;
`uvm_object_utils(your_squence)
...
virtual task body();
your_sequencer x_sequencer;//聲明x_sequencer
...
$cast(x_sequencer,m_sequencer);//動態轉換
...
repeat(10)
begin
`uvm_do_with(m_trans,{your_trans.dmac==x_sequencer.dmac;
your_trans.smac==x_sequencer.smac;})//訪問your_sequencer中的變數
end
...
endclass
如此一來,快遞(your_sequence)上就有了一個標明瞭收貨發貨信息(dmac和smac)的快遞面單,物流公司(driver)就可以按照快遞單來派送了。
但是每次都需要通過聲明x_sequencer,再動態轉換就像人工手寫快遞面單一樣繁瑣,因此uvm將上述過程封裝成立巨集`uvm_declare_p_sequencer,以後就可以自動列印快遞面單了
3、怎麼使用p_sequencer
只需要在你需要的sequence中調用巨集uvm_declare_p_sequencer(SEQUENCER) ,uvm將自動做以下事情:
- 聲明一個x_sequencer,指向SEQUENCER(這裡your_sequencer)。
- 將m_sequencer動態轉換成子類句柄。
你所需要做的只是考慮需要把哪些信息列印到快遞面單上了。
參考資料
1.《UVM實戰 捲Ⅰ》 張強著
2.《晶元驗證漫游指南——從系統理論到UVM的驗證全視界》劉斌著
3. 晶元驗證面試必考題:m_sequencer與p_sequencer的區別是什麼?https://zhuanlan.zhihu.com/p/436911218