加入星計劃,您可以享受以下權益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • sequence介紹
    • sequence中的仲裁任務
    • 與sequence相關的宏
    • sequence進階應用
  • 相關推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

UVM技能點(一)——sequence介紹

2022/05/21
3648
閱讀需 20 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

本文版權歸本公眾號所有。

sequence介紹

 熟悉UVM的朋友應該都知道,sequence的作用是將測試數(shù)據(jù)的產(chǎn)生從driver中分離出來,使得driver能專注于驅動測試數(shù)據(jù)的功能。在不同的測試用例中,將不同的sequence設置成sequencer的main_phase的default_sequence,當sequencer執(zhí)行到main_phase時,發(fā)現(xiàn)有default_sequence,那么它就會啟動這個sequence。之后sequencer將啟動的sequence產(chǎn)生的測試數(shù)據(jù)交給driver,再由driver驅動進入DUT完成仿真。

當完成一個sequence的定義后,就可以使用start任務將其啟動,即在my_case的main_phase中創(chuàng)建自定義的sequence對應的實例,然后調(diào)用sequence.start(sequencer)來啟動。除了直接啟動之外,還可以使用default_sequence啟動。一種是通過在my_case的build_phase使用uvm_config_db設置default_sequence給sequencer,另一種方式是先實例化要啟動的sequence,之后再通過default_sequence啟動。兩者的區(qū)別就在于config_db::set的第四個參數(shù),即要設置的值的獲取方式不同,前者通過type_id::get獲取,后者則直接用實例化后的變量即可。當一個sequence啟動后會自動執(zhí)行sequence的body任務。除body外,它還會調(diào)用sequence的pre_body和post_body任務。

sequence中的仲裁任務

UVM支持同一時刻在一個sequencer上啟動多個sequence,則此時sequencer起到仲裁的作用,即決定使用哪個sequence產(chǎn)生的測試用例。sequencer是根據(jù)transaction的優(yōu)先級來進行仲裁的,通常來說,優(yōu)先級越高越容易被選中。使用uvm_do和uvm_do_with宏時產(chǎn)生的transaction為默認優(yōu)先級,即-1,可以通過uvm_do_pri及uvm_do_pri_with來改變其優(yōu)先級。uvm_do_pri(uvm_do_pri_with同理)第二個參數(shù)為優(yōu)先級,用戶可以自由指定任意大于-1的整數(shù),數(shù)字越大,優(yōu)先級越高。sequencer的仲裁算法有很多種:


 

SEQ_ARB_FIFO,SEQ_ARB_WEIGHTED,SEQ_ARB_RANDOM,SEQ_ARB_STRICT_FIFO,SEQ_ARB_STRICT_RANDOM,SEQ_ARB_USER

若想使得優(yōu)先級設置起作用,應該設置仲裁算法為SEQ_ARB_STRICT_FIFO或SEQ_ARB_STRICT_RANDOM。具體可在測試用例的main_phase中對sequencer進行設置。

此外,除transaction有優(yōu)先級外,sequence本身也有優(yōu)先級概念,不過其本質(zhì)還是設置該sequence產(chǎn)生的transaction的優(yōu)先級。sequence的優(yōu)先級可在啟動sequence時指定,其中第三個參數(shù)即為優(yōu)先級,如


 

seq0.start(env.i_agt.sqr,null,100);

除了設置優(yōu)先級外,sequencer還可以通過sequence的lock操作來改變其行為。所謂lock可以理解為一個發(fā)送transaction的請求,當該請求前面的發(fā)送請求都被仲裁執(zhí)行完畢,sequencer就開始響應lock請求,之后會連續(xù)發(fā)送發(fā)出該請求的sequence的transaction,直到unlock操作被調(diào)用。lock操作在sequence的body中被調(diào)用,當兩個sequence都試圖調(diào)用lock時,先獲得所有權的sequence在執(zhí)行完畢后才會將所有權交給另一個sequence。

在lock之上,還有優(yōu)先級更高的grab操作,不同于lock操作在被調(diào)用后要等待仲裁隊列里的請求執(zhí)行完畢才會被執(zhí)行,grab操作只要一發(fā)出立馬就會被響應,即“插隊”到仲裁隊列最前面——特殊情況是當其他sequence的lock操作正在執(zhí)行中時,grab會等該lock操作執(zhí)行完畢再執(zhí)行。grab操作同樣要ungrab來釋放所有權。當兩個sequence都試圖使用grab操作時,與同時調(diào)用lock操作的判斷規(guī)則一致。

最后,UVM還可以設置sequence,使其在一段時間內(nèi)失效不參與仲裁,這個功能可以通過重載sequence的is_relevant函數(shù)實現(xiàn)。當此函數(shù)返回1說明sequence有效,否則無效。sequence還有個函數(shù)wait_for_relevant也與有效性有關。wait_for_relevant在sequencer發(fā)現(xiàn)其啟動的所有sequence都無效時被調(diào)用,此時sequencer會等待sequence變有效,換言之,可以通過wait_for_relevant來實現(xiàn)該sequence的無效變有效受其他sequence的狀態(tài)影響。

在wait_for_relevant中,必須將使sequence無效的條件清除,否則會陷入死循環(huán),即一直沒有有效的sequence可以執(zhí)行。因此,is_relevant與wait_for_relevant一般應成對重載。

與sequence相關的宏

最基礎的sequence宏是uvm_do及其衍生,uvm_do系列宏主要包含以下八個:


 

uvm_douvm_do_priuvm_do_withuvm_do_pri_withuvm_do_onuvm_do_on_priuvm_do_on_withuvm_do_on_pri_with

從其組織形式可以看出,是uvm_do及pri,with,on等關鍵詞的排列組合,這樣有助于我們?nèi)ビ洃?。回顧一下uvm_do宏的功能,它是UVM中最常用的宏之一,它用于創(chuàng)建一個transaction的實例,將該實例隨機化,

最終將其送個sequencer with關鍵詞給uvm_do宏增加了隨機化的約束條件,pri關鍵詞則設置了發(fā)送的transaction的優(yōu)先級(在上一節(jié)有提到)。uvm_do_on宏用于顯式地指定使用哪個sequencer發(fā)送此transaction,其參數(shù)形式為`uvm_do_on(SEQ_OR_ITEM,SEQR),第一個參數(shù)是transaction的指針,第二個是sequencer的指針。當使用uvm_do時,它實際等價于將uvm_do_on的第二個參數(shù)設置為了默認的sequencer,即此sequence啟動時為其指定的sequencer。uvm_do_on_pri等在此基礎上加上各關鍵詞的功能,與uvm_do_pri與uvm_do之間的關系類似,因此uvm_do系列的宏本質(zhì)上都是uvm_do_on_pri_with的特殊形式。

除了使用uvm_do宏自動產(chǎn)生,隨機化并發(fā)送transaction之外,還可以通過uvm_create宏與uvm_send宏來實現(xiàn)這個過程。uvm_create宏的作用是實例化transaction,當一個transaction被實例化后,可以對其做更多的處理(如隨機化),處理完畢后使用uvm_send宏發(fā)送出去。當然,也可以不用uvm_create而直接使用new函數(shù)來進行實例化。uvm_send也可以增加pri關鍵詞以設置其優(yōu)先級。

此外,還可以將隨機化處理與發(fā)送合并為uvm_rand_send系列宏來實現(xiàn)。這個宏的使用前提是transaction已經(jīng)被分配了空間,即已經(jīng)實例化了。uvm_rand_send宏可增加pri,with關鍵字。設計uvm_rand_send系列宏的意義在于,如果一個transaction占用的內(nèi)存很大,那么很可能希望前后兩次發(fā)送的transaction都使用同一塊內(nèi)存,只是內(nèi)容不同,這樣子比較節(jié)約內(nèi)存空間。

以上都是使用宏來完成transaction發(fā)送相關的工作,但這樣子隱藏了具體的實現(xiàn)細節(jié)。不使用宏產(chǎn)生transaction的方式主要依賴于兩個任務,start_item與finish_item。在使用這兩個任務之前,必須要先實例化transaction后才可以調(diào)用。完整使用如上兩個任務構建一個sequence的代碼如下:


 

virtual task body(); repeat(10) begin tr = new("tr"); start_item(tr); finish_item(tr); endendtask

對transaction進行隨機化的操作可放在實例化之后,finish_item之前的任意位置。start_item和finish_item都可以在調(diào)用時指定優(yōu)先級。

了解了uvm_do宏實現(xiàn)的細節(jié)之后,為了增加uvm_do系列宏的靈活度,UVM提供了三個接口:pre_do,mid_do與post_do。

pre_do是一個任務,在start_item中被調(diào)用,是start_item返回前執(zhí)行的最后一行代碼,在它執(zhí)行完成后才開始對transaction進行隨機化。pre_do有一個1bit參數(shù),用于表明uvm_do是對一個transaction還是一個sequence進行操作(詳見下一節(jié)sequence的嵌套)。

mid_do是一個函數(shù),在finish_item最開始被調(diào)用,在執(zhí)行完此函數(shù)后才會進行finish_item中的其他操作。mid_do有一個參數(shù),表示正在操作的sequence或transaction的指針,但其類型是uvm_sequence_item,需要通過cast轉換成目標類型。

post_do也是一個函數(shù),在finish_item中最后一行代碼被調(diào)用。post_do也有一個參數(shù),與mid_do類似。

 

sequence進階應用

在一個sequence的body中,除了可以使用uvm_do產(chǎn)生transaction外,還可以啟動其他的sequence,這就是sequence的嵌套。嵌套的方式也非常簡單,直接在新的sequence的body任務中調(diào)用定義好的sequence即可,如下所示:

virtual task body();    SEQ0 seq0;\定義化seq0    SEQ1 seq1;\定義化seq1
    repeat(10) begin        `uvm_do(seq0);        `uvm_do(seq1);    endendtask

在上述代碼中,使用了uvm_do宏。uvm_do宏的第一個參數(shù)可以是transaction的指針,此時其調(diào)用start_item和finish_item;該參數(shù)也可以是sequence的指針,此時其調(diào)用該sequence的start任務。除了uvm_do外,前述介紹的uvm_send,uvm_rand_send,uvm_create宏等,其第一個參數(shù)均可以是sequence的指針。

與transaction類似,sequence中也可以加入rand修飾的變量,用以進行對其產(chǎn)生的transaction進行約束。加入了rand變量的sequence可以通過uvm_do_with等宏添加約束條件。不過有一個需要注意的地方,在sequence中定義rand類型變量以向產(chǎn)生的transaction傳遞約束時,變量的名字一定要與transaction中相應字段的名字不同。這是因為如果名字一樣,編譯器就無法正確識別該變量究竟在sequence中還是在transaction中,會產(chǎn)生bug。

一般來說,嵌套sequence能正確的啟動的條件之一是嵌套的所有sequence產(chǎn)生的所有transaction類型需與sequencer能發(fā)送的transaction類型一致。不過有一種方法將兩個不同的transaction交給同一個sequencer處理,那就是將sequencer和driver能夠接受的數(shù)據(jù)類型設置為uvm_sequence_item。


 

class my_sequencer extends uvm_sequencer #(uvm_sequence_item);class my_driver extends uvm_driver #(uvm_sequence_item);

這樣子,在driver接收數(shù)據(jù)時,通過cast將其轉換為不同的transaction類型,即可實現(xiàn)一個sequencer/driver發(fā)送多種類型transaction的功能了。

考慮一種特殊情況,即sequence中產(chǎn)生的transaction受對應的sequencer中變量的約束,此時該如何在sequence中獲取該變量值呢?UVM內(nèi)建了一個宏uvm_declare_p_sequencer(SEQUENCER),這個宏聲明了一個SEQUENCER類型的成員變量,在定義sequence時,使用這個宏聲明對應sequencer的類型如下


 

class case0_sequence extends uvm_sequence #(my_transaction); my_transaction my_trans; `uvm_object_utils(case0_sequence) `uvm_declare_p_sequencer(my_sequencer)endclass

這樣UVM就會自動把m_sequencer(sequence默認sequencer變量,為uvm_sequencer_base類型)轉換為my_sequencer類型,這個過程在pre_body()之前就完成了。這樣在sequence中可以直接使用成員變量p_sequencer,從而獲取my_sequencer中設置的變量值。這個概念比較難理解,讀者可以參考《UVM實戰(zhàn)》6.4.4節(jié),結合具體代碼理解。

由于在同一個項目中各sequence通常都是類似的,因此可以將很多公用的函數(shù)或者任務寫在base_sequence中,其他sequence都從此類派生。sequence是支持派生與繼承的。同時對于使用了uvm_declare_p_sequencer的base_sequence,在派生的sequence中不需要再次聲明,p_sequencer直接成為新的sequence的成員變量。

參考文獻:https://zhuanlan.zhihu.com/p/349791759

相關推薦

電子產(chǎn)業(yè)圖譜