加入星計(jì)劃,您可以享受以下權(quán)益:

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

UVM技能點(diǎn)(一)——sequence介紹

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

本文版權(quán)歸本公眾號(hào)所有。

sequence介紹

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

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

sequence中的仲裁任務(wù)

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


 

SEQ_ARB_FIFO,SEQ_ARB_WEIGHTED,SEQ_ARB_RANDOM,SEQ_ARB_STRICT_FIFO,SEQ_ARB_STRICT_RANDOM,SEQ_ARB_USER

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

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


 

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

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

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

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

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

與sequence相關(guān)的宏

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


 

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等關(guān)鍵詞的排列組合,這樣有助于我們?nèi)ビ洃洝;仡櫼幌聈vm_do宏的功能,它是UVM中最常用的宏之一,它用于創(chuàng)建一個(gè)transaction的實(shí)例,將該實(shí)例隨機(jī)化,

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

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

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

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


 

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

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

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

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

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

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

 

sequence進(jìn)階應(yīng)用

在一個(gè)sequence的body中,除了可以使用uvm_do產(chǎn)生transaction外,還可以啟動(dòng)其他的sequence,這就是sequence的嵌套。嵌套的方式也非常簡(jiǎn)單,直接在新的sequence的body任務(wù)中調(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宏的第一個(gè)參數(shù)可以是transaction的指針,此時(shí)其調(diào)用start_item和finish_item;該參數(shù)也可以是sequence的指針,此時(shí)其調(diào)用該sequence的start任務(wù)。除了uvm_do外,前述介紹的uvm_send,uvm_rand_send,uvm_create宏等,其第一個(gè)參數(shù)均可以是sequence的指針。

與transaction類似,sequence中也可以加入rand修飾的變量,用以進(jìn)行對(duì)其產(chǎn)生的transaction進(jìn)行約束。加入了rand變量的sequence可以通過(guò)uvm_do_with等宏添加約束條件。不過(guò)有一個(gè)需要注意的地方,在sequence中定義rand類型變量以向產(chǎn)生的transaction傳遞約束時(shí),變量的名字一定要與transaction中相應(yīng)字段的名字不同。這是因?yàn)槿绻忠粯樱?a class="article-link" target="_blank" href="/baike/1572830.html">編譯器就無(wú)法正確識(shí)別該變量究竟在sequence中還是在transaction中,會(huì)產(chǎn)生bug。

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


 

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

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

考慮一種特殊情況,即sequence中產(chǎn)生的transaction受對(duì)應(yīng)的sequencer中變量的約束,此時(shí)該如何在sequence中獲取該變量值呢?UVM內(nèi)建了一個(gè)宏uvm_declare_p_sequencer(SEQUENCER),這個(gè)宏聲明了一個(gè)SEQUENCER類型的成員變量,在定義sequence時(shí),使用這個(gè)宏聲明對(duì)應(yīng)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就會(huì)自動(dòng)把m_sequencer(sequence默認(rèn)sequencer變量,為uvm_sequencer_base類型)轉(zhuǎn)換為my_sequencer類型,這個(gè)過(guò)程在pre_body()之前就完成了。這樣在sequence中可以直接使用成員變量p_sequencer,從而獲取my_sequencer中設(shè)置的變量值。這個(gè)概念比較難理解,讀者可以參考《UVM實(shí)戰(zhàn)》6.4.4節(jié),結(jié)合具體代碼理解。

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

參考文獻(xiàn):https://zhuanlan.zhihu.com/p/349791759

相關(guān)推薦

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