[UVM sequence专题] driver中get/get_next_item方法的区别
[UVM sequence专题] driver中get/get_next_item方法的区别
1 driver中的seq_item_port包含的方法
-
driver的
seq_item_port
是uvm_seq_item_pull_port#(REQ,RSP)
类型,是一种双向端口。 -
sequencer的
seq_item_export
是uvm_seq_item_pull_imp #(REQ, RSP, this_type)
类型。
seq_item_port
其包含了以下的内建方法
task get_next_item(output REQ)
task try_next_item(output REQ)
function void item_done(input RSP)
task wait_for_sequence()
function bit has_do_available()
function void put_response(input RSP)
task get(output REQ)
task peek(output REQ)
task put(input RSP)
其中可以看到get_next_item
和 get()
都可以获得REQ item,以下是两者的区别。
2 sequence 中 get_next_item
和 get
方法的区别
两者的区别在dirver与sequencer和sequence的执行关系有关。先说结论吧:
- get_next_item只是获得req fifo中的item,并不会调用item_done
- get除了从fifo中获得item,同时还会直接调用item_done
为什么会区分这种方法呢,可以更加细致的区分应用场景
- 举例来说 get_next_item更适合使用在apb
2.1 get_next_item
的调用细节
在sequence侧发生的事情
- sequence通过
start_item()
方法向sequencer请求仲裁,请求获得权限,在没有被grant之前会一直被阻塞 - start item执行后可以对item进行随机约束,因为此时还没将item送给sequencer
- 然后执行
finish_item
,可以看到主要包含四个部分,mid_do和post_do可以不用关心,是留给用户自定义的回调函数。重要的是另外两个函数sequencer.send_request(item)
这个函数完成的是将item发送给sequencer,将item发送到req fifo中- finish_item会一直阻塞等待driver 侧的item done
在driver侧发生的事情
-
driver在调用get_next_item,尝试从req fifo中取出数据,但实际上get_next_item真正是在哪里执行的呢,实际上是在sequencer中执行的,这与TLM1.0通信有关。port调用get_next_item函数,port的get_next_item函数调用imp的get_next_item函数,imp的get_next_item函数再调用组件的get_next_item函数,归根结底实际上调用的是sequencer中的get函数。可以在UVM源码中看到,get_next_item最终执行的部分是在sequencer中完成的,内容如下:
-
m_req_fifo
虽然是fifo,但实际上也是tlm端口,其类型是uvm_tlm_fifo #(REQ) m_req_fifo;
是在uvm_sequencer_param_base
中定义的
2.2 driver中get的发生的事情
- 可以看到,在driver中调用的seq_item_port.get依旧是最终调用的是sequencer.get
- 其中除了对fifo进行peek以外,还执行了item_done()的操作,也因此,get方法是不会返回RSP的,需要额外调用put_response来返回RSP
RSP是在哪里返回的?
- 对于
get_next_item
来说,RSP是使用item_done(RSP)
来返回的,item done函数内部会调用put_response(在RSP != null的情况下) - 对于
get
来说,get内部调用的item done没有传递参数,所以如果需要返回RSP需要手动调用put函数返回rsp
源码中使用m_req_fifo.peek(t)需要注意的事情
- 使用了peek的方法,代表了并不会数据并不会弹出fifo,而是继续保留在fifo中,直到调用item done之后,数据才会弹出,使用peek获得的是下一个item
- 可以看到,在item done中才对fifo进行了try get。在这之前fifo中的数据没有取出,还只是用的peek
uvm_do 宏调用中发生的事情
what does uvm_do call?
对于 sequence item 而言
先判断是否create,然后可以分为两部分,一部分是start item 和 finish item
- 先调用
uvm_create(item)
- 第一部分:start item
task wait_for_granted()
task parent_sequence.pre_do()
- 第二部分:finish item
function parent_seq.mid_do()
function sequencer.send_request()
task sequencer.wait_for_item_done()
function parent_seq.post_do()
/* This macro takes as an argument a uvm_sequence_item variable or object.
The argument is created using `uvm_create if necessary,
then randomized.
In the case of an item, it is randomized after the call to
uvm_sequence_base::start_item() returns.
This is called late-randomization.
In the case of a sequence, the sub-sequence is started using
uvm_sequence_base::start() with call_pre_post set to 0.
In the case of an item,
the item is sent to the driver through the associated sequencer.
For a sequence item, the following are called, in order */
`uvm_create(item)
sequencer.wait_for_grant(prior) (task)
this.pre_do(1) (task)
item.randomize()
this.mid_do(item) (func)
sequencer.send_request(item) (func)
sequencer.wait_for_item_done() (task)
this.post_do(item) (func)
// For a sequence, the following are called, in order
`uvm_create(sub_seq)
sub_seq.randomize()
sub_seq.pre_start() (task)
this.pre_do(0) (task)
this.mid_do(sub_seq) (func)
sub_seq.body() (task)
this.post_do(sub_seq) (func)
sub_seq.post_start() (task)