UVM sequence的多个用法


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的使用场景绝不仅限于此。

 

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM