UVM sequence 3种启动方式
在build_phase中将某个sequence配置成某个sequencer的动态运行的phase中(如main_phase)的default_sequence, 那么在仿真执行到main_phase的时候,squencer的default_sequence就会启动。第二类:uvm_do_on类。第一类:uvm_do类。
·
start():

- sequence.strat(sequencer,parent_sequence,优先级) ,第一个参数是需要挂载的sequencer;第二个是parent_sequence,一般传入this或者不传入;第三个是优先级;第四个call_pre_post默认为1,则自动执行pre_body/ post_body()函数
- start 执行 pre_start,body等函数。此时就完成了sequence的启动过程。
- 所有sequence都要在sequencer中启动,当sequence启动的时候, 在sequence的 task start 内,会调用 set_item_context() 函数,在 set_item_context() 函数内,会调用 set_sequencer() 函数完成挂载,给m_sequencer赋值
- set_sequencer 函数 会使m_sequencer 句柄指向执行当前 sequence 的 sequencer,即指向 env.vsqr
- 如果没有指定挂载的sequencer,则挂载到parent_sequence的sequencer上
`uvm_do() 宏:
相比直接调用start函数,uvm_do()宏节省了sequence的实例化和随机化的步骤

uvm_do系列宏:

第一类:uvm_do类
- uvm_do:只有一个参数,即产生的transaction
- uvm_do_pri(ority):除了第一个参数transaction外,还有一个参数priority优先级,sequencer的仲裁机制根据transaction的优先级来进行选择。没指定优先级时默认为-1,指定时的数值是大于等于-1的整数,数字越大,优先级越高
- uvm_do_with:第一个参数transaction,第二个参数constraints,在随机化时对transaction的某些字段进行约束
- uvm_do_pri_with:前两者的结合
第二类:uvm_do_on类
- uvm_do_on:on表示展示出来,就是显式地指定产生的这个transaction具体是哪个sequencer来发送。它有两个参数,对应的就是transaction的指针和sequencer的指针。而对于uvm_do而言,它默认的sequencer就是调用uvm_do宏的这个sequence在启动时指定的sequencer
在同一sequencer上启动多个sequence
UVM支持同一时刻在同一sequencer上启动多个sequence,并使用sequence的仲裁机制决定发送顺序
uvm_do 宏 设置 transaction 优先级
- uvm_do 或 uvm_do_with 宏时,产生的 transaction 优先级是默认的优先级(即1)。可通过 uvm_do_pri 及uvm_do_pri_with 改变所产生的 transaction 的优先级
- uvm_do_pri 与 uvm_do_pri_with 的第二个参数是优先级,其数值必须是一个大于等于-1的整数。数字越大优先级越高
- 要使优先级起作用,应设置 sqr 为 SEQ_ARB_STRICT_FIFO 或 SEQ_ARB_STRICT_RANDOM
sequencer的仲裁算法:
- SEQ_ARB_FIFO 默认算法,按照“先入先出”的顺序,不考虑优先级
SEQ_ARB_WEIGHTED 加权的仲裁
SEQ_ARB_RANDOM 完全随机选择
SEQ_ARB_STRICT_FIFO 严格按照优先级,同一优先级的sequence按先入先出的顺序
SEQ_ARB_STRICT_RANDOM 严格按照优先级,同一优先级的sequence随机从最高优先级中选择
SEQ_ARB_USER 用户可以自定义
// sequence
class sequence0 extends uvm_sequence #(my_transaction);
...
virtual task body();
...
repeat (5) begin
`uvm_do_pri(m_trans, 100) // 设置优先级为100
`uvm_info("sequence0", "send one transaction", UVM_MEDIUM)
end
#100;
...
endtask
...
endclass
class sequence1 extends uvm_sequence #(my_transaction);
...
virtual task body();
...
repeat (5) begin
`uvm_do_pri_with(m_trans, 200, {m_trans.pload.size < 500;}) // 设置优先级为200
`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)
end
...
endtask
...
endclass
// case
task my_case0::main_phase(uvm_phase phase);
sequence0 seq0;
sequence1 seq1;
seq0 = new("seq0");
seq0.starting_phase = phase;
seq1 = new("seq1");
seq1.starting_phase = phase
env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO); // 启动优先级配置
fork
seq0.start(env.i_agt.sqr);
seq1.start(env.i_agt.sqr);
join
endtask
seq.start(sqr) 设置 sequence 优先级
sequence启动时指定其优先级
task my_case0::main_phase(uvm_phase phase);
...
env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO); // 启动优先级配置
fork
seq0.start(env.i_agt.sqr, null, 100); // 第一个参数是sequencer,第二个参数是parent sequence(可设为null),第三个参数是优先级,不指定则此值为-1,不能设置为小于-1的数字。
seq1.start(env.i_agt.sqr, null, 200);
join
endtask
default_sequence:
test中将sequence通过config_db机制set到相应的sequencer(virtual sequencer)的main_phase中
在build_phase中将某个sequence配置成某个sequencer的动态运行的phase中(如main_phase)的default_sequence, 那么在仿真执行到main_phase的时候,squencer的default_sequence就会启动
实际上default_sequence会调用start任务,有两种调用方式:
// 方式一
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_config_db#(ubm_object_wrapper)::set(this, // 第一个参数是指定seqr的路径
"env.in_agent.sqr.main_phase", // 第二个参数是指定要执行的phase阶段
"default_sequence", // 第三个参数是指定你的seq
sequence_base::type_id::get()); // uvm_config_db设置default_sequencer
endfunction
// 方式二
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
start_item/finish_item封装函数以及sequence,sequencer,driver的握手关系如下图:
、
更多推荐

所有评论(0)