☰
UVM Sequencer 深度解析:FIFO 深度、req/rsp 应答模型与高频面试坑
2026/10/18 22:56:29 网站建设 项目流程

一、Sequencer 内部FIFO深度

1. 两个核心FIFO(很多人混淆!)

uvm_sequencer 内部维护两套FIFO,不是一个:

  1. request FIFO(req_fifo):存放sequence发过来的transaction(req),给driver拉取。
  2. response FIFO(rsp_fifo):存放driver回传的response事务,给sequence取回。

默认:两个FIFO默认深度都是1!
uvm_sequencer_base里宏定义默认深度UVM_SEQUENCER_DEFAULT_FIFO_DEPTH = 1

含义:

req_fifo深度=1:sequencer最多缓存1个还没有被driver取走的req。

  • 场景:driver正在处理第1笔item;sequence发第2笔item,此时req_fifo满,finish_item()阻塞。
  • 所以默认情况下,sequencer不会预存一大堆激励,基本是一进一出的流水线。

修改FIFO深度

// 在test/env的build_phase,修改sequencer的FIFO深度 seqr.set_depth(8); // req_fifo和rsp_fifo同时改成深度8

注意:set_depth(N)同时修改 req_fifo 和 rsp_fifo。
只改rsp_fifo:seqr.set_rsp_depth(N)

什么时候调大FIFO深度?

  1. Driver处理item很慢,DUT处理时延很长,想让sequence提前产生多笔激励预存在sequencer,提高仿真效率;
  2. 做burst连续激励,避免sequence频繁阻塞等待driver;

⚠️ 坑:
FIFO深度只是缓存上限,不改变握手规则。
就算FIFO深度设为8,driver调用get_next_item拿到item之后,必须item_done才能取下一笔。FIFO只是“仓库”,不是跳过握手。

一句话记忆:
FIFO是缓存,默认深度1;set_depth同时改req和rsp,set_rsp_depth只改响应FIFO。


二、req/rsp 应答模型(两种模式)

两种工作模式

  1. NO_RSP 无应答模式(前面我们示例代码用的)
    sequence只发req,driver处理完item直接item_done(),不返回response。
    item_done()不带参数。
    seq_item_port.item_done(); //无rsp
  2. WITH_RSP 带应答模式(req/rsp完整模型)
    driver处理完DUT事务,构造response事务,回传给sequencer,sequence接收rsp。
    seq_item_port.item_done(rsp); //把rsp传给sequencer

适用场景:读操作!DUT返回读数据、返回状态、error标志。
req:我要读地址0x10;rsp:地址0x10读出的数据=0x55,status=ok。

底层端口:
driver除了seq_item_port(pull req),内部自带response通路:put_response(put端口,push模型,driver推rsp回sequencer的rsp_fifo)。

三、response返回通路:put_response / get_response

1. driver侧:put_response()

两种写法等价:

//写法1:item_done带rsp(推荐,简洁) my_item rsp; rsp = my_item::type_id::create("rsp"); rsp.data = read_data_from_dut; rsp.status = 1'b1; seq_item_port.item_done(rsp); //内部自动调用 put_response(rsp);
//写法2:手动put_response,再调用不带参数item_done seq_item_port.put_response(rsp); seq_item_port.item_done();

⚠️ 重点:不要同时写item_done(rsp) + put_response,会重复发送两份response,引发报错!

2. sequence侧:get_response() 接收应答

sequence发送完finish_item(req)之后,可以调用get_response(rsp)阻塞等待driver返回的rsp。
get_response(rsp):阻塞任务,直到rsp_fifo收到对应response才返回。

完整sequence示例(带rsp):

virtual task body(); my_item req, rsp; req = my_item::type_id::create("req"); start_item(req); req.is_read = 1; req.addr = 16'h0010; finish_item(req); //发送读请求,阻塞等待driver处理 get_response(rsp); //【等待driver返回response】阻塞! `uvm_info("SEQ",$sformatf("read data = %0h, status=%0b",rsp.data,rsp.status),UVM_MEDIUM) endtask

3. req和rsp如何配对?(uvm_sequence_item::transaction_id)

核心:依靠 transaction_id 事务ID匹配req和rsp!

  • sequence发送req时,UVM自动给req分配唯一transaction_id
  • driver构造rsp的时候,必须把rsp.transaction_id = req.transaction_id

如果用item_done(rsp),UVM底层自动帮你拷贝transaction_id,不用手动赋值。

sequencer收到rsp,根据transaction_id找到对应的等待中的sequence,把rsp交给它。

坑:
如果手动put_response,忘记拷贝transaction_id → rsp无法匹配,rsp留在rsp_fifo,get_response永久阻塞卡死。

4. 非阻塞版本:try_get_response()

和try_get_next_item思路一致,function,不阻塞:

if(!this.try_get_response(rsp)) begin //暂时没有rsp,可以做别的事情 end

5. 两个重要开关:set_response_handler / disable_item_done_response_auto

  • p_sequencer.set_response_handler(callback_func)
    注册回调函数,sequencer收到rsp自动调用回调,不用sequence主动调用get_response(异步回调方式)。适合需要异步接收rsp场景。

  • use_sequence_item_response:控制是否开启rsp通路。默认开启。

四、完整带RSP的握手时序图(Mermaid)

DUTdriversequencersequenceDUTdriversequencersequencersp存入rsp_fifo,按transaction_id匹配SEQ拿到rsp,校验数据start_item(req)randomize reqfinish_item(req) 【SEQ阻塞】req送入req_fifoget_next_item(req)拿到请求驱动读命令、地址返回读数据创建rsp,填充数据,自动复制transaction_iditem_done(rsp) //内部put_response(rsp)finish_item 解除阻塞get_response(rsp) //拿应答返回rsp

五、两种rsp使用模式对比

模式说明使用场景
get_response 阻塞等待finish_item之后调用get_response,同步等待rsp,一一对应同步读写,发一个req等一个rsp(最常用)
response_handler回调注册回调函数,rsp到达自动触发函数,不需要get_response异步响应,rsp回来时间不确定

六、高频坑(面试必问)

  1. item_done(rsp) 等价于 put_response(rsp),二选一,不能两个一起写,否则会收到两份rsp,报匹配错误。
  2. transaction_id是req/rsp配对的钥匙;手动put_response必须手动赋值rsp.transaction_id = req.transaction_id。
  3. rsp_fifo满了的时候,driver调用put_response会阻塞。rsp_fifo深度独立可控set_rsp_depth()。
  4. 一个req只能对应一个rsp,不能返回多个rsp;如果DUT返回多个应答,要设计成多个独立transaction。
  5. 不要在NO_RSP模式调用get_response → 永久阻塞卡死。

面试速记

  1. sequencer两个FIFO:req_fifo、rsp_fifo,默认深度都是1;set_depth同时修改两者,set_rsp_depth只修改rsp。
  2. rsp通路:driver用put_response或者item_done(rsp)把response推回sequencer的rsp_fifo。
  3. sequence通过get_response()阻塞获取应答,依靠transaction_id完成req-rsp配对。
  4. 两种rsp模式:同步get_response;异步response_handler回调。

继续往下我们可以讲:

  1. uvm_sequence_item的transaction_id、sequence_id、parent sequence
  2. uvm_sequencer#(REQ,RSP)带两个参数的模板,REQ和RSP类型不同的场景
  3. 异常场景:rsp丢失、rsp乱序、transaction_id冲突仿真报错分析

如果需要请评论或私信~

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询