https://blog.csdn.net/wonder_coole/article/details/90665876
1. UVM sequence機(jī)制的意義
=======================
UVM的sequence機(jī)制最大的作用就是將test case和testbench分離開來造壮。 對一個項目而言,testbench是相對穩(wěn)定的框架蓄拣,而針對各個module要有不同的測試內(nèi)容窒悔,所以具體的test case 的差異非常大搪桂。在UVM中标锄, test和sequence類總是成對出現(xiàn)强衡,實(shí)現(xiàn)了testbench和具體的test case的結(jié)合集漾。test類中可以針對具體的測試內(nèi)容對testbench做一些差異化配置,在sequence類中則是實(shí)現(xiàn)test case的具體細(xì)節(jié)板乙。
所以是偷,大的項目大的團(tuán)隊中,做testbench(test 類以及以下的uvm樹結(jié)構(gòu)等)的是一個團(tuán)隊募逞,對具體module做test case的是另一團(tuán)隊蛋铆。UVM sequence機(jī)制很好的支持不同團(tuán)隊任務(wù)的的分割和結(jié)合。
transaction凡辱,sequence戒职,sequencer栗恩,driver的相互關(guān)系參考下圖
2. UVM sequence細(xì)節(jié)要點(diǎn)
2.1 sequence內(nèi)包含的成員函數(shù)
sequence啟動后透乾,會根據(jù)參數(shù)設(shè)置情況,自動執(zhí)行pre_start(), pre_body(), parent_seq.pre_do(),parent_seq.mid_do(), body(), parent_seq.post_do(), post_body, post_start()等函數(shù)/任務(wù)磕秤。
seq.start (m_sequencer, null, , 1);
// The following methods will be called in start()
seq.pre_start(); (task)
seq.pre_body(); (task) if call_pre_post == 1
parent_seq.pre_do() (task) if parent_seq != null
parent_seq.mid_do(this) (func) if parent_seq != null
seq.body() (task) your code
parent_seq.post_do(this) (func) if parent_seq != null
seq.post_body() (task) if call_pre_post == 1
sub_seq.post_start() (task)
2.2 sequence的三種啟動方式
(1)使用start任務(wù).
task my_case0::main_phase(uvm_phase phase);
case0_sequence cseq;
cseq = new("cseq");
cseq.starting_phase = phase;
cseq.start(env.i_agt.sqr);
endtask
(2)使用uvm_config_db#(uvm_object_wrapper)配置default_sequence
uvm_config_db#(uvm_object_wrapper)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
case0_sequence::type_id::get());
(3)使用uvm_config_db#(uvm_sequence_base)配置default_sequence
function void my_case0::build_phase(uvm_phase phase);
case0_sequence cseq;
super.build_phase(phase);
cseq = new("cseq");
uvm_config_db#(uvm_sequence_base)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
cseq);
endfunction
該示例在uvm1.1可以正常運(yùn)行乳乌,uvm1.2中有問題。
default_sequence最終也是調(diào)用sequence的start任務(wù)市咆。在uvm_sequence_base基類中的start任務(wù)原型是:
virtual task start (
uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
int this_priority = -1,
bit call_pre_post = 1
)
parent_sequence控制這三個任務(wù)/函數(shù)會不會執(zhí)行: parent_seq.pre_do() (task)汉操,parent_seq.mid_do(this) (func),parent_seq.post_do(this) (func) 蒙兰。
call_pre_post控制著pre_body,post_body任務(wù)的執(zhí)行與否磷瘤。
this_priority是發(fā)送給sequencer的transaction的優(yōu)先級值。只能是大于-1的整數(shù)搜变。
2.3 sequence的仲裁機(jī)制
在同一個sequencer上可以啟動多個sequence采缚,每個sequence在啟動時可以指定一個priority值,priority值越大優(yōu)先級越高挠他。設(shè)置方法:
`uvm_do_pri(m_trans, 100)
`uvm_do_pri_with(m_trans, 200, {m_trans.pload.size < 500;})
sequencer默認(rèn)的仲裁算法是SEQ_ARB_FIFO扳抽。所有仲裁算法有6種:
UVM_SEQ_ARB_FIFO : 按transaction的到達(dá)sequencer的順序,先收先處理(FIFO),不考慮優(yōu)先級(default)
UVM_SEQ_ARB_RANDOM : 完全從待處理的仲裁隊列中隨機(jī)選擇贸呢,而無視它們的抵達(dá)順序和優(yōu)先級镰烧。
UVM_SEQ_ARB_STRICT_FIFO : 嚴(yán)格按照優(yōu)先級順序,從仲裁隊列中選擇優(yōu)先級最高的transaction執(zhí)行楞陷。如果仲裁隊列中有多個相同優(yōu)先級的怔鳖,則按FIFO原則選擇其中最先到達(dá)的。
UVM_SEQ_ARB_STRICT_RANDOM : 嚴(yán)格按照優(yōu)先級順序固蛾,從仲裁隊列中選擇優(yōu)先級最高的transaction執(zhí)行败砂。如果仲裁隊列中有多個相同優(yōu)先級的,則從中隨機(jī)選擇魏铅。
UVM_SEQ_ARB_WEIGHTED : 這是最難理解的一個昌犹,其結(jié)果就是高優(yōu)先級的sequence有更大可能獲得sequencer的仲裁權(quán)。具體的仲裁過程是:
a.將仲裁隊列中所有transaction的priority值求和得到sum值
b.之后隨機(jī)產(chǎn)生一個在0到sum之間的一個threshold值
c.從仲裁隊列的最前面開始览芳,依次對每個transaction計算priority的加權(quán)值(將所有該transaction之前的priority值求和)
d.取加權(quán)值最先大于threshold的那個transaction
UVM_SEQ_ARB_USER : 使用用戶自定義的仲裁方法.
注意: 在UVM 1.2, 帶這些宏“UVM_”前綴斜姥; 在 UVM 1.1,不帶“UVM_“前綴.
使用sequencer的成員函數(shù)set_arbitration來配置優(yōu)先級算法:
env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);
仲裁算法詳細(xì)講解可參考:UVM Tutorial for Candy Lovers – 26. Sequence Arbitration
2.4 sequence對sequencer的占用或失效
1. 用lock()和grab()排他性占用sequencer
在sequence的body()中使用lock()...unlock()或grab()...ungrab(), 可以讓在其中間發(fā)送的所有transaction連續(xù)的獲取sequencer的仲裁沧竟,從而連續(xù)的發(fā)送到driver而不被別是sequence打斷铸敏。
二者的區(qū)別僅在仲裁機(jī)制不一樣:
lock會放在仲裁隊列的末尾,sequencer將原來就在仲裁隊列里的transaction發(fā)送完后才執(zhí)行l(wèi)ock的transaction悟泵,一旦lock占用sequencer后杈笔,只有unlock后才釋放。
grab會放在仲裁隊列的最前面糕非,sequencer會立即執(zhí)行g(shù)rab的transaction蒙具,同樣一旦grab占用sequencer后,只有ungrab后才釋放朽肥。
grab實(shí)時性強(qiáng)禁筏,是插隊操作。unlock則不是衡招。
2. sequence的is_revelant函數(shù)和wait_for_relevant任務(wù)篱昔。
sequencer在仲裁時, 會查看sequence的is_relevant函數(shù)的返回結(jié)果始腾, 為1說明此sequence有效并參加仲裁州刽, 否則無效。
可以通過重載is_relevant函數(shù)來使sequence失效浪箭。
當(dāng)sequencer將所有有效transaction發(fā)送完畢后穗椅,它會調(diào)用處于無效狀態(tài)的sequence的wait_for_relevant任務(wù)。當(dāng)wait_for_relevant返回后山林,sequencer還會繼續(xù)調(diào)用is_relevant函數(shù)房待。
在wait_for_relevant任務(wù)中邢羔,user一定要清除sequence的無效狀態(tài)。否則系統(tǒng)會進(jìn)入死循環(huán)桑孩。
2.5 sequence里的宏及start/finish_item任務(wù)
1.uvm_do 相關(guān)宏
在sequence的body中使用uvm_do系列宏拜鹤,可以自動完成transaction的創(chuàng)建,隨機(jī)化和發(fā)送流椒。
uvm_do系列宏對transaction和sequence都能支持敏簿。
如參數(shù)是transaction時它會調(diào)用start_item&finish_item任務(wù)。
如果是sequence宣虾,它會調(diào)用start任務(wù)惯裕。
所有uvm_do宏均由uvm_do_on_pri_with而來,如下圖示:
uvm_do(SEQ_OR_ITEM)
uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)
uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
//uvm_do_on 發(fā)到指定的sequencer
uvm_do_on(SEQ_OR_ITEM, SEQR)
uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)
2. uvm_create及uvm_send系列宏
如果需要在sequence中靈活可控的產(chǎn)生及發(fā)送transaction绣硝,可以uvm_create及uvm_send系列宏蜻势。和uvm_do相比更靈活。
uvm_create(SEQ_OR_ITEM): 工廠模式創(chuàng)建一個transaction或sequence鹉胖,只后用戶應(yīng)該隨機(jī)化握玛,或指定某個值給創(chuàng)建的trans。
uvm_create(SEQ_OR_ITEM,SEQR): 和uvm_create宏一樣甫菠,并且指定了對應(yīng)的sequencer挠铲。
uvm_send(SEQ_OR_ITEM): 將有uvm_create創(chuàng)建的tr/seq發(fā)送出去,其他send宏如下:
uvm_send_pri(SEQ_OR_ITEM, PRIORITY)
uvm_rand_send(SEQ_OR_ITEM)
uvm_rand_send_pri(SEQ_OR_ITEM, PRIORITY)
uvm_rand_send_with(SEQ_OR_ITEM, CONSTRAINTS)
uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS
3. start_item和finish_item任務(wù)寂诱。
uvm_do及
uvm_send宏的最終實(shí)現(xiàn)均是依靠start_item和finish_item任務(wù)來實(shí)現(xiàn)拂苹。調(diào)這兩個任務(wù)可指定優(yōu)先級參數(shù)。
start_item里會調(diào)用wait_for_grant及parent_seq.pre_do任務(wù)痰洒。
finish_item里會調(diào)用mid_do瓢棒,send_request,wait_for_item_down及post_do等
create_item(item)
sequencer.wait_for_grant(prior) (task) \ start_item
parent_seq.pre_do(1) (task) /
`uvm_do* macros
parent_seq.mid_do(item) (func) \ /
sequencer.send_request(item) (func) \finish_item /
sequencer.wait_for_item_done() (task) /
parent_seq.post_do(item) (func) /
2.6 sequence的嵌套/層次化,繼承/派生
嵌套(nested)即在sequence的body中使用另外已經(jīng)定義好的sequence带迟。當(dāng)然需要他們均有一致的transaction類型音羞。執(zhí)行順序參考下圖囱桨。seq2在seq1的body中啟動仓犬,seq1.start()中參數(shù)parent_sequence為空,seq2.start()中參數(shù)parent_sequence為this舍肠。
常用的嵌套搀继,也稱作層次化(sequence hierarchy), 在實(shí)踐中會廣泛用到。 通常對簡單基本的測試場景放在一些基礎(chǔ)sequence里翠语,復(fù)雜場景的sequence均有許多基礎(chǔ)sequence組合而成叽躯。如下圖所示:
正常一種sequence->sequencer->driver只支持一種類型的trans,如果要在同一sequence中向sequencer發(fā)出不同類型的trans肌括,可以:
1)sequencer和driver聲明時要使用基類uvm_sequence_item
2)在driver中,需要將從seq_item_port收到的req使用cast進(jìn)行向下類型轉(zhuǎn)換点骑。
繼承:一般把公用的函數(shù)或任務(wù)放在一個base_sequence,其他sequence均從它派生出來。
3.virtual sequence/sequencer
3.1 p_sequencer
sequence類里有一個uvm_sequencer_base類型m_sequencer指針黑滴,當(dāng)sequence和sequencer關(guān)聯(lián)后憨募,m_sequencer會自動指向該sequencer,但通過m_sequencer不能直接使用seqr里的變量袁辈,否則會出現(xiàn)編譯錯誤菜谣。只能使用cast強(qiáng)制向子類轉(zhuǎn)換后,才能通過m_sequencer.xxx來訪問該seqr內(nèi)的xxx變量晚缩。
UVM引入p_sequencer尾膊,可以自動的實(shí)現(xiàn)上面所述的cast動作,從而可以在sequence中自由使用關(guān)聯(lián)sequencer內(nèi)的變量荞彼。
p_sequencer并不是UVM自動地在sequence的創(chuàng)建的冈敛,需要用戶使用`uvm_declare_p_sequencer宏聲明,之后UVM會自動實(shí)現(xiàn)指向seqr及cast的動作鸣皂。
3.2 什么是virtual sequence/sequencer
在實(shí)際應(yīng)用中莺债,dut往往是很復(fù)雜的系統(tǒng),不單單只有一種接口签夭。而我們testbench中的driver只能驅(qū)動一種接口齐邦,對應(yīng)一種transaction的sequence。如果需要對多個接口同時進(jìn)行激勵第租,就需要的virtual sequence/sequencer措拇。
Virtual sequencer 的特點(diǎn):含有sub sequencer的句柄,用以控制這些sub sequencer慎宾。它并不和任何driver相連 Virtual sequencer丐吓,本身并不處理具體的trans/seq。
Virtual sequence 的作用:和virtual sequencer相關(guān)聯(lián)的就是virtual sequence趟据,它的作用是協(xié)調(diào)不同的subsequencer中sequence的執(zhí)行順序券犁。
Virtual 的含義: 這里的virtual 區(qū)別用 system Verilog中用在function/task/class聲明前,用于修飾的virtual汹碱。virtual sequence/sequencer的virtual主要是指這種sequence/sequencer不像直接作用在具體driver上的sequence/sequencer粘衬,它不處理具體的transaction,主要是來做不同類型sequence間的控制和調(diào)度的咳促。
3.3 實(shí)現(xiàn)virtual sequence/sequencer的步驟
1 :定義virtual sequencer稚新,里面包含各個env里的子sequencer類型的指針。
2 :在base_test里實(shí)現(xiàn)virtual sequencer的例化跪腹,和sub sequencer的連接褂删。
> base_test作為uvm_test_top,即uvm樹形結(jié)構(gòu)的最頂層冲茸,負(fù)責(zé)chip_env和virtual sequencer的規(guī)劃屯阀。
> 實(shí)例化virtual sequencer缅帘。
> 將virtual sequencer與各env的sequencer連接在一起,具體實(shí)現(xiàn)是通過function connect_phase中將virtual sequencer的中個sub sequencer的指針难衰,指向各個具體的sequencer股毫。
3 :定義virtual sequence。
> 在里邊對多個sequence實(shí)例化召衔。
> 要聲明指向?qū)?yīng)的virtual sequencer的p_sequencer,用于使用virtual sequencer中的sub sequencer句柄铃诬。
> 利用`uvm_do_on類型宏,在指定的sub sequencer上運(yùn)行具體的sequence苍凛。
注意:`uvm_do這樣的宏趣席,針對的處理對象,不僅僅是transaction醇蝴,還可以處理sequence宣肚。
######4 :在具體test定義中,利用uvm_config_db將virtual sequencer的default_sequence設(shè)置為具體的virtual sequence悠栓。
*良好的代碼規(guī)范是只在頂層virtual sequence中raise/drop objection霉涨,避免在各底層sequence中使用raise/drop objection引起的混亂。
4. 在sequence中使用config_db
4.1 sequence的完整路徑
除了在uvm樹中的component中用config_db外惭适,在sequence中也可以用笙瑟,雖然sequence是一個uvm_object類。用config_db時癞志,關(guān)鍵在path的參數(shù)往枷,一個sequence的完整路徑,均是有該sequence關(guān)聯(lián)的sequencer和該sequence的實(shí)例對象名組成凄杯。例如如:
sequencer的路徑 + sequence實(shí)例名
uvm_test_top.env.a_agent.a_sequencer.test0_sequence
4.2 在sequence中g(shù)et參數(shù)
1. 在test中設(shè)置sequence中參數(shù)count如:
uvm_config_db#(int)::set(this, "env.i_agt.sqr.*", "count", 9);
注意: 由于sequence實(shí)例化名字不固定错洁,路徑中對應(yīng)的sequence實(shí)例化名字要使用通配符。
2. 在sequence中使用get:
uvm_config_db#(int)::get(null,get_full_name(),"count",count);
注意:其中第一個參數(shù)不能使用this指針戒突,因?yàn)閟equence不是component屯碴,是能使用null/uvm_root::get();
4.3 在sequence中向component或sequence中set參數(shù)
1. 在sequence的body中set參數(shù):
uvm_comfig_db#(bit)::set(uvm_root::get(),"uvm_test_top,env.scb","en_compare",1);
2. 在component/sequence中g(shù)et的方法:
由于component都是在build phase中調(diào)用get函數(shù),如果需要在main phase中g(shù)et該參數(shù)膊存,就需要使用wait_modified任務(wù)不停檢測參數(shù)的變化导而,然后再使用get獲取參數(shù)。
fork
//在這個進(jìn)程中不停檢測參數(shù)的變化
while(1) begin
uvm_comfig_db#(bit)::wait_modified(this,“”膝舅,“en_compare”)
void`(uvm_config_db#(bit)::get(this,"","en_compare",en_compare));
end
// 該component的主體內(nèi)容
begin
......
end
join
5. sequence的response
5.1 成對使用get_reponse/put_reponse任務(wù):
1. 在sequence中使用uvm_do后嗡载,使用get_reponse(rsp)獲得從driver返回的reponse
2. 在driver中,返回一個rsp的方法:
while(1) begin
seq_item_port.get_next_item(req);
drive_it_to_vif(req);
rsp = new("rsp") // 創(chuàng)建 rsp
rsp.set_id_info(req);// 將req的id等信息復(fù)制給rsp
seq_item_port.put_response(rsp); // 返回rsp
seq_item_port.item_done(); // 也可省掉put_reponse的調(diào)用仍稀,直接使用item_done返回,如:
// seq_item_port.item_done(rsp)
end
5.2 返回多個response
driver可以一次返回多個response埂息,要在driver中多次調(diào)用put_response,在sequence中多次調(diào)用get_response.
sequencer內(nèi)部為rsp維護(hù)一個隊列技潘,默認(rèn)深度為8遥巴,所以多次返回超過8各rsp,有溢出的風(fēng)險享幽。
5.3 response的類型
response的類型默認(rèn)是和request的類型一樣的铲掐,如需返回不同類型的response,需要在聲明sequence->sequencer->driver類時傳入req和rsp兩種參數(shù)類型值桩。
5.4 非阻塞形式獲取response
在sequence中使用get_response獲取rsp,是阻塞的方式摆霉。如需非阻塞方式獲取,需要使用response_handler,它會自動的在另外一進(jìn)程中接受response.
1.在sequence中的pre_body()中使用use_reponse_handler()打開該功能奔坟。
2.重載response_handler函數(shù)(類似中斷服務(wù)程序携栋,需要寫入對rsp處理的內(nèi)容),注意:要在里面使用cast強(qiáng)制類型轉(zhuǎn)換
6. sequence library
6.1 seq lib是sequence的集合咳秉,也是繼承自uvm_sequence基類:
class uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequence #(REQ,RSP);
1.聲明seq lib時要指明所產(chǎn)生的transaction類型婉支,
2.seq lib 的new函數(shù)中要調(diào)用init_sequence_library
3.要調(diào)用uvm_sequence_library_utils將seq lib注冊。
4.在單個sequence中要使用宏uvm_add_to_seq_lib將其加入指定seq lib中澜建。
5.可以一對多向挖,也可多對一
6.將seq lib設(shè)為sequencer的default sequence
其他將seq加入seq lib的方法可參考: UVM Sequence Library - Usage, Advantages, and Limitations
6.2 選擇seq的算法:
UVM_SEQ_LIB_RAND: 完全隨機(jī)
UVM_SEQ_LIB_RANDC: random cycle order,先隨機(jī)排序炕舵,再按順序執(zhí)行何之,再保證每個seq執(zhí)行一遍后,執(zhí)行剩余次數(shù)咽筋。
UVM_SEQ_LIB_ITEM: 不執(zhí)行里面的seq帝美,而是自己產(chǎn)生trans,等同于一普通seq
UVM_SEQ_LIB_USER: 用戶自定義晤硕,需重載select_sequence函數(shù)悼潭。
使用config_db 配置方法:
uvm_config_db#(uvm_sequence_lib_mode)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence.selection_mode",
UVM_SEQ_LIB_RANDC);
設(shè)置seq的執(zhí)行次數(shù):min_random_count & max_random_count, 默認(rèn)都是10
6.3 sequence library的執(zhí)行過程
seqence library和sequence舞箍,也是調(diào)用start任務(wù)執(zhí)行舰褪,只后順序執(zhí)行seq lib的pre_start,pre_body, body,post_body,post_start。在seq lib的body中疏橄,按照配置的random的方式啟動各個sequence占拍。在調(diào)用start任務(wù)啟動sequence時,給參數(shù)call_pre_post傳入0值捎迫,因此每個sequence的pre_body 和 post_body不會運(yùn)行晃酒。
6.4 使用uvm自帶的sequence_library_cfg 統(tǒng)一配置lib里的參數(shù)
參考:
版權(quán)聲明:本文為CSDN博主「wonder_coole」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議窄绒,轉(zhuǎn)載請附上原文出處鏈接及本聲明贝次。
原文鏈接:https://blog.csdn.net/wonder_coole/java/article/details/90665876