UVM——sequence機制(資料激勵的產生、配置方式)
阿新 • • 發佈:2022-04-14
文章目錄
- 一、sequence的執行流程
- 二、sequence的啟動方式——start()/default_sequence
- 二、sequence生產資料——body( )
- 三、config_db配置sequence
一、sequence的執行流程
-
uvm_sequence_item
包裝資料
):只能對資料進行封裝,不存在自動執行的函式; -
uvm_sequence(
生產資料
):具有可自動執行的函式,可通過body()函式進行可執行操作,產生資料激勵; -
uvm_sequencer(
傳送資料
):將資料傳送給driver;
sequence item是每一次driver與DUT互動的最小粒度內容,在sequence與driver之間起到橋樑作用的是sequencer,sequencer與driver均是component元件,它們之間的通訊也是通過TLM埠實現的。UVM序列的連線傳送如下圖所示:
-
sequence物件自身會產生目標數量的sequence item物件
- 產生的sequence item會經過sequencer再流向driver。
- driver得到了每一個sequence item,經過資料解析,再將資料按照與DUT的物理介面協議寫入到介面上,對DUT形成有效激勵。
- 必要時,driver在每解析並且消化完一個sequence item,也會將最後的狀態資訊同sequence item物件本身再度返回給sequencer,最終抵達sequence物件一側。這麼做的目的在於,有的時候sequence需要得知driver與DUT互動的狀態,這就需要driver仍然有一個迴路再將處理了的sequence item物件和狀態資訊寫回到sequence一側。
二、sequence的啟動方式——start()/default_sequence
UVM中sequence的啟動分為顯示啟動和隱式啟動兩種方式。
- 顯式啟動(直接啟動)——呼叫start()方法啟動。
- 隱式啟動 ——使用uvm_config_db機制配置default_sequence啟動。
//sequence的顯式啟動
//該方法提起和落下objection,通過phase.raise_objection(this)/phase.drop_objection(this)
my_sequence seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(sequencer);
phase.drop_objection(this)
//sequence的隱式啟動
//該方法可以在sequence中使用starting_phase提起和撤銷objection
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase",
"default_sequence",
case0_sequence::get_type());
//在my_sequence中的body任務中
virtual task body;
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat(10)begin
`uvm_do(req);
end
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
二、sequence生產資料——body( )
當一個sequence啟動後,會自動執行body()函式生產資料
,sequencer會將資料傳送給driver,完成資料的傳送。sequencer與driver的通訊也是通過TLM埠實現的,TLM埠在例化中需要對通訊引數進行指定,這裡的通訊引數即sequence item種類。
class tr_sequence extends uvm_sequence#(transaction);
...
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this,"starting"); //1.啟動模擬,生產資料
`uvm_do(req); //2.通過巨集`uvm_do自動隨機化產生資料
if(starting_phase != null)
starting_phase.drop_objection(this,"done"); //3.結束模擬
endtask
endclass
class driver extends uvm_driver#(transaction);
...
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); //4.driver申請資料
send(req); //5.按照物理時序處理接收到的資料
seq_item_port.item_done(); //6.資料傳輸完畢
end
endtask
endclass
-
加粗樣式在sequence中,通過
objection機制
控制模擬時的資料生產; - 在driver的run_phase階段,利用TLM埠
seq_item_port
的get_next_item()和item_done()方法
控制資料包的傳輸;
2.1.巨集`uvm_do( )的功能
當一個sequence啟動後,會自動執行sequence中的body任務,在body任務中可以呼叫`uvm_do系列巨集來生產資料。
當同一個sequencer上啟動多個sequence時,由於sequencer會依據何種選擇啟用哪一個sequence的transaction存疑,故引入仲裁機制。使用仲裁機制的相關係列巨集如下所指示:(預設仲裁演算法是SEQ_ARB_FIFO,遵循先入先出,不考慮優先順序)
`uvm_do(SEQ_OR_ITEM) //1. 根據sequence_item例項,隨機化產生資料
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS) //2. 在隨機化資料的基礎上,新增約束
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR) //3. 隨機化同時,顯式的指定使用哪個sequencer來發送此transaction
`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)
- `uvm_do系列巨集其實是將下述動作封裝在了一個巨集中(start_item與finish_item運用)。在實際的程式碼編寫中,工程師可以不使用巨集uvm_do()處理資料,而是根據實際情況手動執行這些內嵌程式。
req = my_sequence::type_id::create("req"); \ 1. 建立item物件例項;
start_item(req); \ 2.獲取sequencer的授權許可;
assert(req.randomzie() with {req.data == 100;}); //assert(req.ranomzie()); 3.**對item進行隨機化處理**;
finish_item(req); \ 4.將item傳送至sequencer,進而完成與driver之間的互動
- 巨集`uvm_do_with (item, { constraint })與 巨集 ‘uvm_do( )無本質區別,只是多了約束條件;需要說明的是巨集‘uvm_do( )不支援randc型別的隨機變數。
2.2.sequence的巢狀啟動
巢狀sequence的啟動可以通過start(m_sequencer)來完成,也可以通過uvm_do()系列巨集來完成;
-
m_sequencer是base_sequencer啟動時所使用的sequencer的指標
,也就是說,巢狀的seq啟動時所使用的sequencer同所在的sequence所使用的sequencer一致。
class base_sequence extends uvm_sequence#(transaction);
...
virtual task body();
crc_seq cseq=crc_seq::type_id::create("cseq");
long_seq lseq=long_seq:;type_id::create("lseq");
repeat(10)begin
cseq.start(m_sequencer); //啟動巢狀的seq
lseq.start(m_sequencer);
end
endtask
endclass
- 採用uvm_do巨集啟動巢狀的seq,更加簡單;
class base_sequence extends uvm_sequence#(transaction);
...
virtual task body();
crc_seq cseq;
long_seq lseq;
repeat(10)begin
`uvm_do(cseq); //啟動巢狀seq
`uvm_do(lseq);
end
endtask
endclass
2.3.sequence接收響應rsp
class tr_sequence extends uvm_sequence#(transaction);
...
virtual task body();
...
`uvm_do(req);
get_response(rsp); //3.接收響應資訊rsp
endtask
endclass
class driver extends uvm_driver#(transaction);
...
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
send(req);
rsp = transaction::type_id::create("rsp");
rsp.set_id_info(req); //1. 建立並配置響應ID
seq.item.port.item_done(rsp); //2. driver返回響應rsp
end
endtask
endclass
三、config_db配置sequence
3.1.預設執行的sequence
預設的測試用例(test_base)執行預設的default sequence
,該sequence在驗證環境中配置的;
class environment extends uvm_env; //在初始環境中配置預設的sequence
...
function void build_phase(uvm_phase phase);
...
uvm_config_db #(uvm_object_wrapper)::set(this,"*.seqr.main_phase","default_sequence",transaction_sequence::get_type());
...
endfunciton
endclass
預設sequence在main_phase
階段執行,此時也可將null賦給default sequence,不產生資料。
3.2.配置sequence——get_full_name() / m_sequencer
- 通過
get_full_name( )
獲取配置的路徑名稱,可以有效防止不同的sequence中有相同變數進行配置時產生的衝突。 - get_full_name()在sequence中被呼叫時,列印的路徑為:uvm_test_top.env.agt.seqr.seq;
- 需要說明的是,當sequence在virtual sequence中被啟動,呼叫的get_full_name()方法列印的路徑結果:uvm_test_top.v_seqr.*,這是由於virtual sequence不遵循UVM樹的路徑層次;
class tr_sequence extends base_sequence; //2.在底層元件捕獲sequence配置
int item_count = 10;
...
virtual task pre_start();
...
uvm_config_db #(int)::get(null, "this.get_full_name()", "item_count", item_count); //本地變數item_count = 20,配置成功
//uvm_config_db #(int)::get(null, this.get_full_name(), "item_count", item_count); get_full_name() 不新增引號
//uvm_config_db #(int)::get(m_sequencer, “”, "item_count", item_count); m_sequencer 指定路徑
endfunciton
endclass
class test_20_items extends test_base; //1.在測試用例中啟動sequence配置
...
function void build_phase(uvm_phase phase);
...
uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20); //item_count = 20 ,啟動配置賦值
endfunciton
endclass
3.3.配置sequence——get_sequncer()
- 通過
get_sequencer( )
獲取配置欄位的sequencer,可以為sequencer下的所有sequence中的相同變數同時提供配置。
class tr_sequence extends base_sequence; //2.在底層元件捕獲sequence配置
int item_count = 10;
...
virtual task pre_start();
...
uvm_config_db #(int)::get(this.get_sequencer(),"","item_count",item_count); //本地變數item_count = 20,配置成功
endfunciton
endclass
class test_20_items extends test_base; //1.在測試用例中啟動sequence配置
...
function void build_phase(uvm_phase phase);
...
uvm_config_db #(int)::set(this,"env.agt.seqr.*","item_count",20); //item_count = 20 ,啟動配置賦值
endfunciton
endclass