本篇介紹UVM中的sequence,這是UVM中最基礎的部分。對于前面介紹的uvm_callback, uvm_visitor等,很少被使用到或者也只有搭建平臺的人會使用。不能認為平臺的搭建更富有“技術含量”,用例的構建有時候更重要。UVM提供了多種方式,常常讓使用者混淆,本篇將會 “捋” 一下sequence_item,sequence,sequencer,driver的協作關系,結合設計模式中的命令模式,中介模式,橋接模式進行介紹。
啟動與掛載
基本理解:UVM中各個組件的相互“交流”是基于實際業務提取出的transaction(uvm_sequence_item);uvm_sequence中的body()函數負責產生發送這些transaction,生命周期是body()函數的執行期;uvm_sequencer負責調度從uvm_sequence中拿到的transaction,然后發送給driver;uvm_sequcence和transaction一樣,也是繼承于uvm_sequence_item,uvm_sequcne是transaction的有機結合,代表一種具體的業務行為,描述一種scenario 這樣更有利于在創建用例時的復用。同時在transaction,uvm_sequence中加入SV特有的語法特點,constrain約束,方便擴展使用到不同的場景。
啟動:這里的啟動就是通過哪種方式調用uvm_sequence中的body()函數的意思。(body()函數被sequence的 start()函數調用,也可以理解成 start()函數的執行)
sequence的掛載:uvm_sequence不屬于component,沒有phase概念,需要掛載在一個sequencer上,在這個sequencer的phase中被調用(default_sequence的情形),同時uvm_sequence可以操作所掛載的sequencer的成員變量( *比如在sequence中使用sequencer中的寄存器模型句柄;在virtual sequence中調用 virtual sequcner中的其他 sequcner 句柄 * )。
transaction的掛載:對于transaction,掛載的意思就是將transaction發送給所掛載的sequencer,sequencer再發送給連接的driver。(無論sequence還是transaction,掛載的本質就是給uvm_sequence_item中的成員變量 m_sequencer賦值,sequence/transaction都繼承于uvm_sequence_item)
( *啟動,掛載在UVM英文文檔中沒有對應關鍵詞,僅是根據實際使用總結出來的詞匯 * )
繼承關系:
三種sequence的啟動方式:
1. start()函數顯示調用
使用形式:
在sequence中顯示調用strat()函數,第一個參數是需要掛載的sequencer;第二個是parent_sequence,一般傳入this或者不傳入;第三個是優先級;第四個call_pre_post默認為1,則自動執行pre_body/ post_body()函數
執行pre_start,body等函數。此時就完成了sequence的啟動過程。
在start()函數中,首先調用了函數set_item_context()函數,這個函數位于sequence的父類uvm_sequence_item中,負責給成員變量m_sequencer, m_parent_sequence賦值。
如果沒有指定掛載的sequencer,則掛載到parent_sequence的sequencer上。
此處seq0顯示傳入了需要掛載的p_sqr0,則調用set_sequencer()函數完成掛載,給m_sequencer賦值。
set_sequencer()函數會調用m_set_p_sequencer(),這個函數是一個空的虛函數。如果在sequence中調用了宏uvm_declare_p_sequencer則會重寫這個函數,將成員變量p_sequencer指向sequence所掛載的sequencer上。所以使用者要保證start()函數傳入的sequencer應該和宏 uvm_declare_p_sequencer聲明的類型一致。否則$cast轉換的時候會報錯。
使用uvm_declare_p_sequencer后,就可以在sequence中調用掛載sequencer的成員函數和成員變量了。
2. `uvm_do()宏
**使用形式: **
UVM中提供了多個宏,uvm_do,uvm_do_with,`uvm_do_on_with等,但最終都是調用了uvm_do_on_pri_with宏。uvm_do_on_pri_with宏第一個參數可以傳入sequence,也可以傳入transaction。
uvm_do_on宏第一參數是sequence。uvm_do_on_pri_with宏中調用宏uvm_create_on。
create_item通過工廠模式創建sequence實例
調用set_item_context()函數,給成員變量m_sequencer, m_parent_sequence賦值,參考上節分析。此處parent_sequence默認是this。
調用sequence的start函數,流程和上節一樣,最后調用body()函數。
通過宏的形式相比于直接調用start函數,節省了sequence的實例化和隨機化的步驟,但是對于不熟悉宏的人來說,宏封裝的內容可能與其使用意圖偏差。
3. default_sequence方式
使用形式:
第一種:
第二種:
使用default_sequence的方式也是通過工廠模式創建sequence,再隱式的調用seq.start(this) 函數
【拓展】
對于sequence中的資源訪問,可以參考 UVM設計模式 (三) 靜態類、資源管理、uvm_event、uvm_*_pool、uvm_config_db、UVM_REGEX_NO_DPI 中的"sequence中的資源訪問"小節,總結了5種使用方式。
命令模式
Comand Pattern:將一個請求(命令)封裝成一個對象,從而可以用不同的請求對接收者進行參數化,實現請求的發送者和接收者解耦;還可以對請求排隊,或者記錄請求日志,以及支持撤銷操作。
命令模式和前面提到的策略模式很相似,也是通過“組合 + 多態”實現的。設計模式更關注于設計意圖,也就是應用場景,單純地從代碼實現上看,有些模式確實很相似,比如命令模式和策略模式。但策略模式是不同策略具有相同的目的,不同的實現,相互之間可以替換,在命令模式中,是不同的命令具有不同的目的,對應不同的邏輯處理,相互之間不可替換。
一個簡單的示例:captain是命令的發起者,soldier是命令的接收者。
start_item finish_item
上節提到使用uvm_do宏啟動sequence,如果宏傳入的第一個參數不是uvm_sequence_base類型,就是我們的transaction, 則調用start_item, finish_item函數。
start_item()三個參數,第一個是傳入的transaction, 第二個是優先級,第三個是指定該transaction發送給哪一個sequencer, transaction掛載在哪一個sequencer上。
如果之前沒有給transaction的m_sequencer賦值,此處sequcner仍未null
調用get_sequencer()函數,將transaction掛載到sequence啟動的sequencer上。
transaction必須指定掛載的sequencer, 否者transaction無法通過sequencer發送給driver。而sequence卻不一定需要掛載到sequencer上,因為sequence的主要目的是執行body函數,直接在tc中調用seq.start()不指定sequencer,也可以。但是default_sequence的形式必須掛載到sequencer上。
set_item_context()函數上節已提到。wait_for_grant()等待sequencer仲裁。pre_do() hook函數。
在finish_item中,調用transaction掛載sequencer的函數send_request(), 這個函數定義在uvm_sequencer_param_base中。將transaction放入m_req_fifo容器中。
當driver中調用**seq_item_port.get_next_item(req)**時,實際調用的是uvm_sequencer中的get_next_item函數。從m_req_fifo容器中拿到之前sequence放入的transaction。
driver中的seq_item_port.item_done(),實際調用的是uvm_sequencer中的item_done函數。sequence通過wait_for_item_done和sequencer的item_done握手,通過成員變量m_wait_for_item_sequence/transaction_id判斷。每個sequence, sequence中的每個transaction其ID都是唯一的。
如果item_done()傳入rsp,調用put_response函數,與sequence中的get_response配合使用。
start_item/finish_item封裝函數以及sequence,sequencer,driver的握手關系如下圖:
結合命令模式,sequence作為命令的發起者,sequencer作為接收者。sequence負責發送各種transaction, 至于是哪一個sequencer接收,由transaction中的成員變量m_sequencer決定。
實現發送者與接收者的解耦。設計模式側重應用場景,transaction僅僅是事務,不具備命令的實現行為,所以UVM的實現并不完全符合命令模式。
UVM中的sequencer更像一個仲裁者,一邊是driver不斷請求transaction,一邊根據priority給sequcence授權,接收sequence發送的transaction,支持lock,grab操作。同時driver,sequence之間也有聯系,driver可以response transaction給sequence。
在實際使用中,建議不要使用宏,而是通過start()函數顯示啟動sequence, 通過start_item finish_item發送transaction。
中介者模式
Mediator Pattern:定義一個單獨的(中介)對象,來封裝一組對象之間的交互。將這組對象之間的交互委派給與中介對象操作,來避免對象之間的直接交互,使耦合松散。
如果不使用中介者模式,各個系統模塊,或者說各個類之間,互相依賴,就會形成一個復雜的網裝結構;使用了中介者模式,系統就變成了結構清晰的星形結構。
UVM中virtual sequence就是一個典型的中介者模式的使用案列。在virtual sequence中可以統一調度各個sequence,負責每個sequence的同步,成員變量賦值,隨機約束等。中介者模式實現簡單,具體示例不在演示。
審核編輯:劉清
-
轉換器
+關注
關注
27文章
8625瀏覽量
146862 -
寄存器
+關注
關注
31文章
5317瀏覽量
120003 -
耦合器
+關注
關注
8文章
718瀏覽量
59635 -
UVM
+關注
關注
0文章
181瀏覽量
19138 -
sequence
+關注
關注
0文章
23瀏覽量
2831
原文標題:UVM設計模式 (七)命令模式、三種sequence啟動方式、start_item/finish_item、中介模式
文章出處:【微信號:數字芯片設計工程師,微信公眾號:數字芯片設計工程師】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論