UVM Sequencer 深度解析:FIFO 深度、req/rsp 应答模型与高频面试坑

一、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深度

systemverilog 复制代码
// 在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()不带参数。

    systemverilog 复制代码
    seq_item_port.item_done(); //无rsp
  2. WITH_RSP 带应答模式(req/rsp完整模型)
    driver处理完DUT事务,构造response事务,回传给sequencer,sequence接收rsp 。

    systemverilog 复制代码
    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()

两种写法等价:

systemverilog 复制代码
//写法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);
systemverilog 复制代码
//写法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):

systemverilog 复制代码
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,不阻塞:

systemverilog 复制代码
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)

DUT driver sequencer sequence DUT driver sequencer sequence #mermaid-svg-mnR6K5cv89O613dk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mnR6K5cv89O613dk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mnR6K5cv89O613dk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mnR6K5cv89O613dk .error-icon{fill:#552222;}#mermaid-svg-mnR6K5cv89O613dk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mnR6K5cv89O613dk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mnR6K5cv89O613dk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mnR6K5cv89O613dk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mnR6K5cv89O613dk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mnR6K5cv89O613dk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mnR6K5cv89O613dk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mnR6K5cv89O613dk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mnR6K5cv89O613dk .marker.cross{stroke:#333333;}#mermaid-svg-mnR6K5cv89O613dk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mnR6K5cv89O613dk p{margin:0;}#mermaid-svg-mnR6K5cv89O613dk .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mnR6K5cv89O613dk text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-mnR6K5cv89O613dk .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-mnR6K5cv89O613dk .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-mnR6K5cv89O613dk .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-mnR6K5cv89O613dk .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-mnR6K5cv89O613dk #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-mnR6K5cv89O613dk .sequenceNumber{fill:white;}#mermaid-svg-mnR6K5cv89O613dk #sequencenumber{fill:#333;}#mermaid-svg-mnR6K5cv89O613dk #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-mnR6K5cv89O613dk .messageText{fill:#333;stroke:none;}#mermaid-svg-mnR6K5cv89O613dk .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mnR6K5cv89O613dk .labelText,#mermaid-svg-mnR6K5cv89O613dk .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-mnR6K5cv89O613dk .loopText,#mermaid-svg-mnR6K5cv89O613dk .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-mnR6K5cv89O613dk .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-mnR6K5cv89O613dk .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-mnR6K5cv89O613dk .noteText,#mermaid-svg-mnR6K5cv89O613dk .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-mnR6K5cv89O613dk .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mnR6K5cv89O613dk .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mnR6K5cv89O613dk .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-mnR6K5cv89O613dk .actorPopupMenu{position:absolute;}#mermaid-svg-mnR6K5cv89O613dk .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-mnR6K5cv89O613dk .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-mnR6K5cv89O613dk .actor-man circle,#mermaid-svg-mnR6K5cv89O613dk line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-mnR6K5cv89O613dk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} rsp存入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冲突仿真报错分析

如果需要请评论或私信~

相关推荐
聪明的笨猪猪6 小时前
AI应用架构选型:架构师的核心决策困境与权衡
经验分享·面试·架构
疯华整猫8 小时前
被杀掉之后:我把 Android 的「唤起 + 常驻」重做了一遍
前端·面试·架构
nice_lcj5209 小时前
Java 并发容器入门:ConcurrentHashMap、CopyOnWriteArrayList、阻塞队列
java·面试·并发编程·阻塞队列·concurrenthashmap·copyonwritearraylist
岁月宁静21 小时前
AI 应用开发工程师简历怎么写:HR 初筛、技术复筛、面试追问,三道关卡各看什么?
人工智能·python·面试
Dream it possible!1 天前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
Pniubi1 天前
力扣560.和为k的子数组
算法·leetcode·职场和发展
Pniubi1 天前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
yeccheng1 天前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
j7~1 天前
【C++ 八股文】(篇四)C++11 新特性
开发语言·c++·面试·c++11·八股文
nice_lcj5202 天前
Java Lambda 表达式入门:怎么写、怎么用、常用方法有哪些
java·开发语言·后端·面试