1.sequence的啟動方式
1.sequence完成定義和實例化后,調用start任務直接啟動,一般不用;
2.default_sequence,這種方式有兩種調用方式,分別是:
1 uvm_config_db#(uvm_object_wrapper)::set(null,"$full_path(sequencer.main_phase)","default_sequence",xx_sequence::type_id::get());
1 function xx::build_phase(uvm_phase phase); 2 super.build_phase(phase); 3 xx_sequence m_xx_sequence; 4 m_xx_sequence = new("m_xx_sequence"); 5 uvm_config_db#(uvm_sequence_base)::set(null,"$full_path","default_sequence",m_xx_sequence); 6 7 endfunction
兩種方式的實現有差別,第一種的默認方式寫死了,比如你是在env下面使用這個sequence作為default,那么在具體的case里面再設是沒用的了,
第二種方式允許在具體的case里面再進行設置default_sequence。
所以,我們一般不要在env下面去設置默認的sequence,具體case具體的驅動反而實用。
2.sequence的仲裁機制
1.同一個case啟動多個sequence
1 fork 2 m_seq0.start($full_path(sqr)); 3 m_seq1.start($full_path(sqr)); 4 join
現象是sequence0和sequence1里面的transaction交替發送到sequencer,經由sequencer發給driver。(sequence0/1使用uvm_do后者uvm_do_with);
2.優先級的仲裁機制
UVM內部包含自己的一套對於sequence的仲裁算法。使用uvm_do_pri或者uvm_do_pri_with。
相較於uvm_do/uvm_do_with,多了一個參數,數值大於-1,越高代表優先級越大。
但是如果單純的使用這個參數的話,會發現還是交替發送,因為UVM有很多的仲裁算法,默認的SEQ_ARB_FIFO是先進先出的,加權無效。
所以需要對sequencer的set_arbitration這個進行選擇具體的仲裁算法。
1 $full_path(sequencer).set_arbitration(XXX);
仲裁算法有:SEQ_ARB_FIFO,SEQ_ARB_WEIGHTED,SEQ_ARB_RANDOM,...等等。
3.lock操作
某個sequence的請求比較特殊,當這個sequence獲得執行權,希望一直連續的發送transaction給driver,這時候就需要用到lock操作;
用法:在具體的sequence中,在需要lock操作的前面進行lock,uvm_do結束后unlock掉;
4.grap操作
與lock操作類似,不同的是他一出現就擁有了sequencer的所有權,優先級最高,並且等待執行完才釋放;lock不會,lock會等待隊列中先處理完
再進行lock
5.失效操作
某個sequence希望在一段時間內不參與仲裁; sequence的is_relevant()函數的返回值為1說明有效,反之無效,可以通過具體場景設置其值來使
sequence失效。
3.virtual suquence
virtual用來解決sequence之間的同步問題,也是sequence之間的執行順序問題。使用virtual sequence用來調度其他sequence,本身不發送transaction,
具體的做法如下:
1 //vsqr 2 class vsqr extends uvm_sequencer; 3 xx_sequencer0 m_xx_sequencer0; 4 xx_sequencer1 m_xx_sequencer1; 5 xx_sequencer2 m_xx_sequencer2; 6 .... 7 endclass 8 9 //base case 10 class base_test extends uvm_test; 11 vsqr m_vsqr; 12 env m_env; 13 .... 14 endclass 15 16 function void xx_test::build_phase(uvm_phase phase); 17 super.build_phase(phase); 18 m_vsqr = vsqr::type_id::create("m_vsqr",this); 19 ... 20 endfunction 21 22 function void xx_test::connect_phase(uvm_phase phase); 23 super.connect_phase(phase); 24 m_vsqr.m_xx_sequencer0 = m_env.i_agt.sqr; 25 m_vsqr.m_xx_sequencer1 = m_env.i_agt.sqr; 26 ... 27 endfunction 28 29 //case0 30 class case0 extends uvm_sequence; 31 `uvm_object_utils(case0) 32 `uvm_declare_p_sequencer(m_vsqr) 33 34 virtual task body(); 35 xx_trans m_xx_trans; 36 xx_sequence0 m_xx_sequence0; 37 xx_sequence1 m_xx_sequence1; 38 `uvm_do_on(m_xx_sequence0,p_sequencer.m_xx_sequencer0); 39 `uvm_do_on(m_xx_sequence1,p_sequencer.m_xx_sequencer1);
40 ... 41 endtask 42 ... 43 endclass
4.sequence宏
1.uvm_do系列
uvm_do(xx_trans)
uvm_do_pri(xx_trans,pri_num)
uvm_do_with(xx_trans,{xx_trans.xx = xx; xx_trans.xx = xx;})
uvm_do_pri_with(xx_trans,pri_num,{xx_trans.xx = xx;})
uvm_do_on(xx_trans,xx_sqr)
uvm_do_on_pri(xx_trans,xx_sqr,pri_num)
uvm_do_on_with(xx_trans,xx_sqr,{xx_trans.xx = xx;})
uvm_do_on_pri_with(xx_trans,xx_sqr,pri_num,{xx_trans.xx = xx;})
2.嵌套的sequence
假設已經定義了兩個sequence:sequence0、sequence1,現在想產生一個新的
sequence,這個新的sequence發的包是sequence0、sequence1交替產生。
1 class sequence2 extends uvm_sequence #(xx_trans); 2 ... 3 virtual task body(); 4 sequence0 m_sequence0; 5 sequence1 m_sequence1; 6 repeat(10) begin 7 `uvm_do(m_sequence0) 8 `uvm_do(m_sequence1) 9 end 10 endtask 11 endclass
上述例子意味着uvm_do系列宏第一個參數可以是sequence的指針。
3.在sequence中使用隨機值
一般情況下,我們習慣在transaction中產生隨機值發送給driver,然后在具體sequence使用uvm_do_with對
一些我們需要自己定義的參數進行賦值約束,其實也可以在sequence里面使用rand bit xx;這種寫法,只不過在
sequence里面的變量名要和transaction里的變量名區分,因為編譯器首先到transaction里面尋找。
5.在sequence中使用config_db獲取參數
1.sequence路徑問題
config_db對於sequence機制提供了支持,可以使用config_db設置一些比如發包的長度,數量等等。由於
sequence不在UVM樹中,那么如何設置config_db的路徑呢?可以使用get_full_name()在sequence的pre_body
一般路徑為:uvm_test_top.xx_env.xx_agent.xx_sequencer.xx_sequence
uvm_config_db#(xx)::get(null,uvm_test_top.xx_env.xx_agent.xx_sequencer.xx_sequence,"xx",xx);
2.wait_modified
假設sequence希望在處理一些異常情況的時候發出一個信號給scoreboard,scoreboard會實時監測這個信號,
一旦起來了,進行相應的比對。如何實現這種機制?
使用wait_modified,sequence使用uvm_config_db::set發,scoreboard使用uvm_config_db:wait_modified
等待收。
1 task xx_scoreboard::main_phase(uvm_phase phase); 2 ... 3 fork 4 while(1) begin 5 uvm_config_db#(xx)::wait_modified(null,"$full_path()","xx"); 6 ... 7 end 8 join 9 ... 10 endtask
wait_modified的使用場景絕不僅限於此。