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