UVM基礎(chǔ)-Sequence、Sequencer(二)
?目錄
????????sequence和sequencer
????????將sequence掛載到sequencer
????????將item掛載到sequencer?
????????????????宏定義使用實(shí)例
????????sequencer仲裁特性
????????????????實(shí)例
????????sequencer的鎖定機(jī)制
????????virtual sequence
????????layering sequence
????????在上篇博客中,講了sequencer和driver之間傳遞sequence item的握手過(guò)程,也講了sequence和item之間的關(guān)系,下面我們來(lái)講講sequence和sequencer之間的關(guān)系,以及當(dāng)多個(gè)sequence掛載到sequencer時(shí)沖裁這么處理。
sequence和sequencer
將sequence掛載到sequencer
將sequence掛載到sequencer上:
? ? ? ? uvm_sequence::start(uvm_sequencer_base sequencer,? ?uvm_sequence_base parent_sequence = null,?int this_priority = -1, bit call_pre_post = 1)
????????第一個(gè)變量,是指明sequence要掛載到哪個(gè)sequencer上面;第二個(gè)sequence是默認(rèn)當(dāng)前的sequence是沒(méi)有parent sequence的;第三個(gè)參數(shù)默認(rèn)值是-1,會(huì)使得該sequence如果有parent_sequence會(huì)繼承其優(yōu)先級(jí)值,如果它是頂層sequence,則其優(yōu)先級(jí)會(huì)被自動(dòng)設(shè)置為100,用戶(hù)也可以自己指定優(yōu)先級(jí)數(shù)值;第四個(gè)參數(shù)建議使用默認(rèn)值,這樣body() 函數(shù)預(yù)定義的回調(diào)函數(shù),uvm_sequence::pre_body()和uvm_sequence::post_body()兩個(gè)方法會(huì)在uvm_sequence::body()的前后執(zhí)行。
? ? ? ? 在上面的代碼中,child_seq被嵌套在top_seq中,所以在掛載的時(shí)候,需要指明它的parent_sequence;而在test一層調(diào)用top_seq時(shí),由于它是root sequence,所以不需要再指定parent sequence;另外,在調(diào)用掛載sequence時(shí),需要對(duì)這些sequence進(jìn)行例化。

將item掛載到sequencer?
發(fā)送方法是將item掛載到sequencer上:
? ? ? ? uvm_sequence::start_item(uvm_sequence_item item, int set_priority = -1, uvm_sequencer_base sequencer = null);
? ? ? ? uvm_sequence::finish_item(uvm_sequence_item item, int set_priority = -1);
????????在使用上面的一堆start&finish item方法時(shí),需要使用create_item來(lái)對(duì)item進(jìn)行創(chuàng)建,以及對(duì)其進(jìn)行隨機(jī)化處理。
對(duì)比start()方法和start_item()/finish_item()方法,要注意,它們面向的掛載對(duì)象是不同的。在執(zhí)行start()的過(guò)程中,默認(rèn)情況下會(huì)執(zhí)行sequence的pre_body()和post_body(),但是如果start()的參數(shù)call_pre_post = 0,那么就不會(huì)執(zhí)行。

發(fā)送item和sequence相關(guān)的宏:

? ? ? ? 上面為UVM宏定義,每個(gè)宏所對(duì)應(yīng)要做的事情,打x的為要做。uvm_create(item) + uvm_send(item)的功能可以等效為uvm_do(item) 。
? ? ? ? 用戶(hù)可以通過(guò)`uvm_do/`uvm_do_with來(lái)發(fā)送無(wú)論是sequence還是item。這種不區(qū)分對(duì)象sequence還是item的方式,帶來(lái)了不少便捷,但容易讓新手不知道這些宏定義背后做了那些工作,因此,需要先了解它們背后的sequence和item各自發(fā)送的方法。
? ? ? ? 不同的宏,可能會(huì)包含創(chuàng)建對(duì)象的過(guò)程,也可能不會(huì)創(chuàng)建對(duì)象。比如`uvm_do/`uvm_do_with會(huì)創(chuàng)建對(duì)象,而`uvm_send則不會(huì)創(chuàng)建對(duì)象,也不會(huì)將對(duì)象做隨機(jī)處理,因此需要了解它們各自包含的執(zhí)行內(nèi)容和順序。
? ? ? ? `uvm_do宏使用的場(chǎng)景只有在sequence中才可以使用,因?yàn)槠渲猩婕傲艘恍┱{(diào)用sequence中定義的方法,因此不能在其他例如uvm_test、uvm_env中調(diào)用sequence相關(guān)的宏定義。
宏定義使用實(shí)例
? ? ? ? 盡量要避免使用fork-join_any和for-join_none來(lái)控制sequence的發(fā)送順序,因?yàn)橥顺鰂ork-join塊之后,在執(zhí)行后續(xù)的操作時(shí),可能有sequence還沒(méi)發(fā)送完畢,那么在用戶(hù)想終止后臺(tái)運(yùn)行的sequence線程而使用disable時(shí),可能會(huì)在不合適的時(shí)間點(diǎn)鎖住sequencer。
????????如果一定要使用fork-join_any和for-join_none來(lái)控制sequence的發(fā)送順序,應(yīng)當(dāng)在使用disable之前,對(duì)各個(gè)sequence線程的后臺(tái)狀況保持關(guān)注,盡量在發(fā)完item完成握手之后再終止sequence;如果要使用fork-join,那么應(yīng)當(dāng)確保有方法可以讓sequence線程在滿足一些條件后停止發(fā)送item。否則只要有一個(gè)sequence線程無(wú)法停止,則整個(gè)fork-join無(wú)法退出。
sequencer仲裁特性

在實(shí)際使用中,我們可以通過(guò)uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)函數(shù)來(lái)設(shè)置仲裁模式,這里的仲裁模式UVM_SEQ_ARB_TYPE有如下幾種值可以選擇:
? ? ? ? ※ UVM_SEQ_ARB_FIFO:默認(rèn)模式,來(lái)自sequences的發(fā)送請(qǐng)求,按照FIFO先進(jìn)先出的方式被依次授權(quán),和優(yōu)先級(jí)沒(méi)有關(guān)系,誰(shuí)先申請(qǐng),誰(shuí)就獲得。
? ? ? ? ※ UVM_SEQ_ARB_STRICT_FIFO:先看優(yōu)先級(jí),再看順序,優(yōu)先級(jí)高的先發(fā)送,優(yōu)先級(jí)一致的,優(yōu)先授權(quán)先申請(qǐng)的sequence。
? ? ? ? ※ UVM_SEQ_ARB_WEIGHTED:不同sequence的發(fā)送請(qǐng)求,按照它們的優(yōu)先級(jí)權(quán)重隨機(jī)授權(quán)。
? ? ? ? ※ UVM_SEQ_ARB_RANDOM:不同的請(qǐng)求會(huì)被隨機(jī)授權(quán),而無(wú)視它們的抵達(dá)順序和優(yōu)先級(jí)。
? ? ? ? ※ UVM_SEQ_ARB_STRICT_RANDOM:不同的請(qǐng)求,會(huì)按照它們的最高優(yōu)先級(jí)隨機(jī)授權(quán),與抵達(dá)時(shí)間無(wú)關(guān)。
? ? ? ? ※ UVM_SEQ_ARB_USER:用戶(hù)可以自定義仲裁方法user_priority_arbitration()來(lái)裁定哪個(gè)sequence的請(qǐng)求被優(yōu)先授權(quán)。
實(shí)例
輸出結(jié)果:?

? ? ? ? ?由于將seq1和seq2設(shè)置為同樣的高優(yōu)先級(jí)(500),而seq3設(shè)置為較低的優(yōu)先級(jí)(300),這樣在隨后的UVM_SEQ_ARB_STRIC_FIFO仲裁模式下,可以從輸出結(jié)果看到,按照優(yōu)先級(jí)高低和傳送請(qǐng)求時(shí)間順序,先將seq1和seq2中的item發(fā)送完畢,隨后再將seq3發(fā)送完。
sequencer的鎖定機(jī)制
? ? ? ? uvm_sequencer提供了兩種鎖定機(jī)制,分別通過(guò)lock()和grab()方法實(shí)現(xiàn),這兩種方法的區(qū)別在于:
? ? ? ? lock()和unlock()這一對(duì)方法可以為sequence提供排外的訪問(wèn)權(quán)限,但前提條件是,該sequence首先需要按照sequencer的仲裁機(jī)制獲得授權(quán)。而一旦sequence獲得授權(quán),則無(wú)需擔(dān)心權(quán)限被收回,只有該sequence主動(dòng)解鎖(unlock)它的sequencer,才可以釋放這一鎖定的權(quán)限。lock()是一種阻塞任務(wù),只有獲得了權(quán)限,它才會(huì)返回。
? ? ? ? grab()和ungrab()也可以為sequence提供排外的訪問(wèn)權(quán)限,而且它只需要在sequencer下一次授權(quán)周期時(shí)就可以無(wú)條件地獲得授權(quán)。與lock方法相比grab方法無(wú)視同一時(shí)刻內(nèi)發(fā)起傳送請(qǐng)求的其他sequence,而唯一可以組織它的只有已經(jīng)預(yù)先獲得授權(quán)的其他lock或者grab的sequence。
? ? ? ? 如果sequence使用了lock()或者grab()方法,必須在sequence結(jié)束前調(diào)用unlock()或者ungrab()方法來(lái)釋放權(quán)限,否則sequencer會(huì)進(jìn)入死鎖狀態(tài)而無(wú)法繼續(xù)為其余sequence授權(quán)。
實(shí)例
輸出結(jié)果:

? ? ? ? 之所以seq1和seq2都在10ns的時(shí)候發(fā)送一次,而不是發(fā)送兩次,是因?yàn)樵诎l(fā)送item時(shí),延遲了10ns再發(fā)送。然后lock_sequence鎖住sequencer,發(fā)送三次item。
? ? ? ? 從這段代碼中,我們知道,grab_sequence在20ns的時(shí)候,就已經(jīng)開(kāi)始申請(qǐng)sequencer了(實(shí)際上seq1、seq2、seq3也同時(shí)發(fā)起了請(qǐng)求),但是在40ns才獲得sequencer,這是因?yàn)閟equencer被lock_sequence鎖住了。等到40ns,unlock之后才被grab。被grab后,發(fā)送三次item,到70ns,ungrab。seq1、seq2、seq3再根據(jù)優(yōu)先級(jí)依次發(fā)送item。
virtual sequence
????????virtual sequence可以承載不同目標(biāo)sequencer的sequence群落,組織協(xié)調(diào)這些sequence的方式類(lèi)似于高層次的hierarchical sequence。virtual sequencer和普通的sequencer有很大的不同,它起到了橋接其他sequencer的作用,即virtual sequencer是一個(gè)鏈接所有底層sequencer句柄的地方,是一個(gè)中心化的路由器。
? ? ? ? virtual sequencer本身不會(huì)傳送item數(shù)據(jù)對(duì)象,因此virtual sequencer不需要與任何driver進(jìn)行TLM鏈接。所以用戶(hù)需要在頂層connect階段,做好virtual sequencer中各個(gè)sequencer句柄與底層sequencer實(shí)體對(duì)象的一一對(duì)接,避免句柄懸空。
? ? ? ? 在virtual sequence中使用uvm_do_on把不同sequence掛載到不同的sequencer上面,而不是想hierarchical sequence那樣直接用uvm_do默認(rèn)把sequence掛載到頂層。
? ? ? ? 對(duì)于virtual sequence而言,它可以承載各個(gè)子模塊環(huán)境的element sequence,而最后通過(guò)virtual sequencer中的各個(gè)底層sequencer句柄,各個(gè)element sequence可以分別掛載到對(duì)應(yīng)的底層sequencer上。
? ? ? ? 使用`uvm_declare_p_sequencer,可以在后臺(tái)新建一個(gè)p_sequencer變量,而將m_sequencer的默認(rèn)變量(uvm_sequencer_base類(lèi)型)通過(guò)動(dòng)態(tài)轉(zhuǎn)換($cast),變?yōu)轭?lèi)型virtual_sequencer的p_sequencer。
????????這種中心化的協(xié)調(diào)方式,使得頂層環(huán)境在場(chǎng)景創(chuàng)建和激勵(lì)控制方面更加得心應(yīng)手,而且在代碼后期維護(hù)中,測(cè)試場(chǎng)景的可讀性也得到了提高。
使用virtual sequence時(shí)容易遇到的錯(cuò)誤:
? ? ? ? ※ 需要區(qū)分virtual sequence 同其它普通sequennce(element sequence、hierarchical sequence)
? ? ? ? ※ 需要區(qū)分virtual sequencer同其它底層負(fù)責(zé)傳送數(shù)據(jù)對(duì)象的sequencer。
? ? ? ? ※ 在virtual sequence中記得使用宏`uvm_declare_p_sequencer來(lái)創(chuàng)建正確類(lèi)型的p_sequencer變量,方便接下來(lái)各個(gè)目標(biāo)的sequencer索引。
? ? ? ? ※ 在頂層環(huán)境中記得創(chuàng)建virtual sequencer,并且完成virtual sequencer中各個(gè)sequencer句柄與底層sequencer的跨層次鏈接,避免句柄懸空。
layering sequence
? ? ? ? 在構(gòu)建更加復(fù)雜的協(xié)議總線傳輸,例如PCIe,USB3.0等,那么通過(guò)一個(gè)單一的傳輸層級(jí)會(huì)對(duì)以后的激勵(lì)復(fù)用、上層控制不那么友好。對(duì)于這種更深層次化的數(shù)據(jù)傳輸,在實(shí)際中無(wú)論是VIP還是自開(kāi)發(fā)的環(huán)境,都傾向于通過(guò)若干抽象層次的sequence群落來(lái)模擬協(xié)議層次。
? ? ? ? 通過(guò)層次化的sequence可以分別構(gòu)建transaction layer、transport layer和physical layer等從高抽象級(jí)到低抽象級(jí)的transaction轉(zhuǎn)化。這種層次化的sequence構(gòu)建方式,我們稱(chēng)之為layering sequence。例如在進(jìn)行寄存器級(jí)別的訪問(wèn)操作,其需要通過(guò)transport layer轉(zhuǎn)化,最終映射為具體的總線傳輸。
? ? ? ? layering sequence會(huì)包含三部分,高抽象層次的item、低抽象層次的item、中間作轉(zhuǎn)化的sequence。
? ? ? ? 在各個(gè)抽象級(jí)的sequencer中,需要有相應(yīng)的轉(zhuǎn)換方法,將從高層次的transaction從高層次的sequencer獲取,繼而轉(zhuǎn)換為低層次的transaction,最終通過(guò)低層次的sequencer發(fā)送出去。例如adapter_seq負(fù)責(zé)從layer_sequencer獲取layer_trans,再將其轉(zhuǎn)換為phy_master_sequencer一側(cè)對(duì)應(yīng)的sequence或者transaction,最后將其從phy_master_sequencer發(fā)送出去。