news 2026/10/15 14:08:10

UVM sequence-driver 通信模型(详细讲解)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVM sequence-driver 通信模型(详细讲解)

UVM sequence-driver 通信模型(详细讲解)

核心一句话:sequence 负责产生激励事务(item),driver 负责把事务变成硬件信号打给DUT;两者通过uvm_seq_item_pull_port/export握手通信,属于pull模型(driver主动拉取item),这是UVM默认标准模型。

一、整体角色分工

  1. sequence(uvm_sequence):激励发生器,写在body()里,创建seq_item,把item交给sequencer。不直接访问DUT信号
  2. sequencer(uvm_sequencer):中间“快递中转站”。有FIFO缓存,接收sequence发来的item,等待driver来取。
    • 端口:uvm_seq_item_pull_imp #(TR, this_type) seq_item_export;
  3. driver(uvm_driver):从sequencer拿transaction,解析item,驱动接口信号到DUT。
    • 端口:uvm_seq_item_pull_port #(TR) seq_item_port;
  4. seq_item(uvm_sequence_item):事务数据包,存放激励数据、控制位(addr/data/wr_en等),纯数据载体

UVM树简易结构(Mermaid)

seq_item_port ↔ seq_item_export

uvm_test_top: test_case

my_sequencer

my_driver

my_sequence

virtual interface -> DUT

连接关系:driver.seq_item_port.connect(sequencer.seq_item_export);
sequence 挂载到 sequencer:seq.start(seqr);

二、通信端口类型:pull端口(重点!)

uvm_seq_item_pull_port包含两组API,对应两个握手动作:

  1. get_next_item(req):driver向sequencer申请拿新item(阻塞)
  2. item_done():driver告知sequencer当前item传输完成

✅ 这就是经典2步握手,是sequence-driver最核心通信机制。

完整通信时序(标准2步握手流程)

1. sequence 执行 `start_item(item)` → 请求sequencer分配权限,阻塞等待sequencer空闲 2. sequence 执行 `finish_item(item)` → 将item发送给sequencer的内部FIFO,等待driver取走 ===== 上面是sequence侧;下面driver侧循环 ===== 3. driver 中 `seq_item_port.get_next_item(req);` → driver阻塞,去sequencer拉取item。 如果sequencer还没有item,driver停在这里等(阻塞) 4. driver拿到req(seq_item),解析里面的数据,驱动DUT接口信号 5. 驱动完成后,调用 `seq_item_port.item_done();` → 通知sequencer:这个item处理完毕! → sequencer收到item_done后,唤醒sequence,sequence继续产生下一笔激励 6. driver回到循环,再次调用 get_next_item,取下一个item,往复循环

⚠️ 关键点:
get_next_item()和item_done()必须成对出现,不能丢、不能乱序!
get_next_item拿到item之后,在item_done之前,sequencer不会给driver下一个item

三、代码最简可运行Demo(带逐行注释)

1. 事务 my_item.sv

class my_item extends uvm_sequence_item; `uvm_object_utils(my_item) rand bit [7:0] data; function new(string name="my_item"); super.new(name); endfunction endclass

2. Sequence (产生激励)

class my_seq extends uvm_sequence#(my_item); `uvm_object_utils(my_seq) `uvm_declare_p_sequencer(my_sequencer) //绑定sequencer类型 function new(string name="my_seq"); super.new(name); endfunction virtual task body(); my_item req; repeat(3) begin //产生3笔transaction req = my_item::type_id::create("req"); start_item(req); //【1】请求sequencer权限,阻塞 assert(req.randomize()); finish_item(req); //【2】把item发给sequencer,等待driver取完+item_done `uvm_info("SEQ",$sformatf("send item data = %0d",req.data),UVM_MEDIUM) end endtask endclass

3. Sequencer

class my_sequencer extends uvm_sequencer#(my_item); `uvm_component_utils(my_sequencer) function new(string name="my_sequencer",uvm_component parent=null); super.new(name,parent); endfunction endclass

4. Driver(从sequencer拉item,驱动DUT)

class my_driver extends uvm_driver#(my_item); `uvm_component_utils(my_driver) virtual my_intf vif; function new(string name="my_driver",uvm_component parent=null); super.new(name,parent); endfunction virtual task run_phase(uvm_phase phase); my_item req; forever begin //【3】driver主动拉取item,没有item就阻塞等待 seq_item_port.get_next_item(req); // 把item数据驱动到DUT接口 vif.data <= req.data; #10ns; `uvm_info("DRV",$sformatf("drive DUT data=%0d",req.data),UVM_MEDIUM) //【5】通知sequencer:当前item处理完成! seq_item_port.item_done(); end endtask endclass

5. Environment + Test

class my_env extends uvm_env; `uvm_component_utils(my_env) my_sequencer seqr; my_driver drv; function new(string name="my_env",uvm_component parent=null); super.new(name,parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); seqr = my_sequencer::type_id::create("seqr",this); drv = my_driver::type_id::create("drv",this); endfunction virtual function void connect_phase(uvm_phase phase); super.connect_phase(phase); //【端口连接!】driver端口连sequencer的export drv.seq_item_port.connect(seqr.seq_item_export); uvm_config_db#(virtual my_intf)::set(this,"drv","vif",top.vif); endfunction endclass class test1 extends uvm_test; `uvm_component_utils(test1) my_env env; function new(string name="test1",uvm_component parent=null); super.new(name,parent); endfunction virtual function void build_phase(uvm_phase phase); super.build_phase(phase); env = my_env::type_id::create("env",this); endfunction virtual task run_phase(uvm_phase phase); my_seq seq; phase.raise_objection(this); seq = my_seq::type_id::create("seq"); seq.start(env.seqr); //sequence挂载sequencer启动 phase.drop_objection(this); endtask endclass

四、两种握手方式:2步握手 vs 1步get模型

✅ 模型A:2步握手(get_next_item + item_done,最常用)

优点:driver拿到item后可以花费任意长时间驱动DUT(多周期激励)
缺点:必须成对调用,写错容易卡死仿真(死锁)

✅ 模型B:一步getseq_item_port.get(req)

等价于:get_next_item+ 自动内部调用item_done
适合:单周期简单激励,driver拿到item立刻处理完。

限制:拿到item之后不能跨周期驱动,不适合复杂时序激励。

seq_item_port.get(req); //内部自动完成 item_done,不需要手动写item_done

五、常见坑(面试高频考点)

  1. 死锁场景1:调用get_next_item,忘记写item_done()
    → sequencer永远等待ack,sequence卡在finish_item,仿真卡死。
  2. 死锁场景2:多次连续调用get_next_item,中间没有item_done
    → 一次只能持有1个transaction,不支持预取多个。
  3. sequence不调用start_item/finish_item,直接seq_item_port.put
    → put是push模型(sequence主动推item),不是UVM默认pull模型,很少用。
  4. 端口方向搞反:drv.seq_item_export.connect(seqr.seq_item_port)直接报错

    port(请求方driver)连 export(提供方sequencer)

六、Pull模型 vs Push模型(区分)

  • Pull模型(默认,sequence-seqr-driver):Driver主动拉
    Driver是主控,什么时候取激励由driver决定,适合DUT有backpressure(反压)场景,DUT忙的时候driver可以慢一点取item。
  • Push模型:sequence主动put推送给driver
    sequence主控,强制把item塞给driver,driver被动接收,很少在激励通路使用。

七、面试常问总结

  1. sequence和driver不直接相连,中间必须经过sequencer
  2. 通信端口是uvm_seq_item_pull_port,标准是pull模型
  3. 标准两步握手:get_next_item()拿item → 驱动DUT →item_done()确认完成
  4. sequencer内置FIFO缓存transaction,可以支持多个sequence并发(virtual sequence)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 14:06:48

C++学生管理系统结课作业:从类设计到文件持久化的完整避坑指南

简介&#xff1a;东北大学C结课大作业学生管理系统是一份完整的课程设计项目资源&#xff0c;面向需要完成学生信息管理系统的C初学者和结课学生。系统以Student类为核心&#xff0c;实现了学生数据的录入、查询、修改、删除及文件持久化&#xff0c;并覆盖面向对象、数据结构、…

作者头像 李华
网站建设 2026/10/15 14:05:27

TGS2011插件:嵌入式轻量级2D图形渲染引擎实战指南

简介&#xff1a;这是一套专为TGS2011传奇服务端深度定制的综合性功能插件包&#xff0c;面向游戏服务端开发者、私服搭建者及MUD类RPG系统二次开发者&#xff0c;解决传统TGS服务端功能单一、扩展性弱、玩家交互体验不足等核心问题。资源共664个文件&#xff0c;涵盖174个smp&…

作者头像 李华
网站建设 2026/10/15 14:05:01

NAS 部署 Octopus 聚合网关:统一管理多个大模型 API 的完整指南

1. 为什么要在 NAS 上折腾 Octopus 这层“中间人”手里攒了三四个大模型 API Key 的人&#xff0c;大概率都经历过这种场面&#xff1a;写代码时开着 DeepSeek 的文档&#xff0c;调试 Agent 时切到智谱的页面&#xff0c;跑翻译任务又得翻出另一个平台的密钥&#xff0c;浏览器…

作者头像 李华
网站建设 2026/10/15 14:04:19

MCP 生产级安全隔离:基于 RBAC 的跨部门工具访问权限矩阵设计

上周四下午三点半&#xff0c;财务系统的告警群突然炸了锅。一条来自结算系统的异常平账流水被风控探针截获&#xff0c;追踪调用链路发现&#xff0c;罪魁祸首居然是运营部门刚刚上线灰度的“爆款选品投放 Agent”。这个本该只在只读库里捞商品转化率的智能体&#xff0c;在多…

作者头像 李华
网站建设 2026/10/15 14:03:39

CoPaw桌面版一键安装与高效部署实战指南

1. 项目概述&#xff1a;CoPaw桌面版的核心价值CoPaw作为一款面向Windows平台的桌面应用&#xff0c;其"一键安装"特性彻底改变了传统软件部署的复杂流程。我在实际测试中发现&#xff0c;这个仅35MB的安装包能在90秒内完成从下载到可用的全过程&#xff0c;相比同类…

作者头像 李华