# [UVM实战review] sequence
[UVM实战review] sequence
启动sequence方式总结
-
default sequence 方式,不实例化
uvm_config_db#(uvm_obejct_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case0_sequence::type_id::get())
-
先例化sequence,再通过default sequence启动
// 在case的build phase中set config db
function case0_test::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
- 除此以外就是在case中显示创建sequence然后start了。
仲裁机制
可以在同一个sequencer上启动多个sequence,默认情况下会交替产生trans,uvm_do_pri
marco could change the priority.pri越高,优先级越大。
设置完优先级并不代表所有高的trans一定比低优先级的trans先发送,这个与sequencer的仲裁算法有关。
SEQ_ARB_FIFO, // default
SEQ_ARB_WEIGHTED, // 加权仲裁
SEQ_ARB_RANDOM, // 完全随机选择
SEQ_ARB_STRICT_FIFO, // 是严格按照优先级的,当有多个同一优先级的sequence时,按照先入先出的顺序选择
SEQ_ARB_STRICT_RANDOM // 是严格按照优先级的,当有多个同一优先级的sequence时,随机从最高优先级中选择
SEQ_ARB_USER // 则是用户可以自定义一种新的仲裁算法
// HOW TO SET?
// in case main phase or run phase
env.i_agt.set_arbitration(SEQ_STRICT_FIFO)
lock and grab
lock
当其前面的所有请求被处理完毕后,sequencer就开始响应这个lock请求,此后sequencer会一直连续发送此sequence的
transaction,直到unlock操作被调用。lock请求前所有的trans执行完了之后才响应,给发起lock请求的sequence独占,等这个sequence unlock了,再响应别的sequence
grab
优先级更高,直接放在仲裁队列最前面,不管前面trans先完成就直接拥有所有权。
sequence marco
`uvm_do(SEQ_OR_ITEM)
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR)
`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_on_pri_with on对应的是seqr,pri是优先级,with是约束
uvm_rand_send意义
uvm_rand_send系列宏及uvm_send系列宏的意义主要在于,如果一个transaction占用的内存比较大,那么很可能希望前后两次发送的transaction都使用同一块内存,只是其中的内容可以不同,这样比较节省内存。
pre_do mid_do post_do 与 start_item finish_item关系
pre_do is task, post_do and mid_do is function.
sequencer.wait_for_grant(prior) (task) \ start_item \
parent_seq.pre_do(1) (task) / \
` uvm_do* macros
parent_seq.mid_do(item) (func) \ /
sequencer.send_request(item) (func) \ finish_item /
sequencer.wait_for_item_done() (task) /
parent_seq.post_do(item) (func) /
嵌套sequence
当约束很多的时候,单纯总constraint来入手会导致维护起来很麻烦,可以使用嵌套sequence,子sequence产生不同的trans,在顶层body只需要将m_sequencer设置为子sequence的start参数就可以
p_sequencer
由于m_sequencer
是uvm_sequencer_base类型的,所以不能索引到sequncer的成员变量,需要使用``uvm_declare_p_sequencer(SEQUENCER_TYPE)`来进行转换
virtual sequencer
virtual的含义在于其统一调度的意思,自身不发送trans,只是控制别的sequence。对应的需要有virtual sequencer。