资讯动态

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

发布时间:2026/10/15 14:08:16 来源:尧图企业网站定制
UVM sequence-driver 通信模型详细讲解核心一句话sequence 负责产生激励事务itemdriver 负责把事务变成硬件信号打给DUT两者通过uvm_seq_item_pull_port/export握手通信属于pull模型driver主动拉取item这是UVM默认标准模型。一、整体角色分工sequenceuvm_sequence激励发生器写在body()里创建seq_item把item交给sequencer。不直接访问DUT信号sequenceruvm_sequencer中间“快递中转站”。有FIFO缓存接收sequence发来的item等待driver来取。端口uvm_seq_item_pull_imp #(TR, this_type) seq_item_export;driveruvm_driver从sequencer拿transaction解析item驱动接口信号到DUT。端口uvm_seq_item_pull_port #(TR) seq_item_port;seq_itemuvm_sequence_item事务数据包存放激励数据、控制位addr/data/wr_en等纯数据载体UVM树简易结构Mermaidseq_item_port ↔ seq_item_exportuvm_test_top: test_casemy_sequencermy_drivermy_sequencevirtual interface - DUT连接关系driver.seq_item_port.connect(sequencer.seq_item_export);sequence 挂载到 sequencerseq.start(seqr);二、通信端口类型pull端口重点uvm_seq_item_pull_port包含两组API对应两个握手动作get_next_item(req)driver向sequencer申请拿新item阻塞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还没有itemdriver停在这里等阻塞 4. driver拿到reqseq_item解析里面的数据驱动DUT接口信号 5. 驱动完成后调用 seq_item_port.item_done(); → 通知sequencer这个item处理完毕 → sequencer收到item_done后唤醒sequencesequence继续产生下一笔激励 6. driver回到循环再次调用 get_next_item取下一个item往复循环⚠️ 关键点get_next_item()和item_done()必须成对出现不能丢、不能乱序get_next_item拿到item之后在item_done之前sequencer不会给driver下一个item三、代码最简可运行Demo带逐行注释1. 事务 my_item.svclass my_item extends uvm_sequence_item; uvm_object_utils(my_item) rand bit [7:0] data; function new(string namemy_item); super.new(name); endfunction endclass2. Sequence 产生激励class my_seq extends uvm_sequence#(my_item); uvm_object_utils(my_seq) uvm_declare_p_sequencer(my_sequencer) //绑定sequencer类型 function new(string namemy_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 endclass3. Sequencerclass my_sequencer extends uvm_sequencer#(my_item); uvm_component_utils(my_sequencer) function new(string namemy_sequencer,uvm_component parentnull); super.new(name,parent); endfunction endclass4. Driver从sequencer拉item驱动DUTclass my_driver extends uvm_driver#(my_item); uvm_component_utils(my_driver) virtual my_intf vif; function new(string namemy_driver,uvm_component parentnull); 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 endclass5. Environment Testclass my_env extends uvm_env; uvm_component_utils(my_env) my_sequencer seqr; my_driver drv; function new(string namemy_env,uvm_component parentnull); 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 nametest1,uvm_component parentnull); 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模型✅ 模型A2步握手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调用get_next_item忘记写item_done()→ sequencer永远等待acksequence卡在finish_item仿真卡死。死锁场景2多次连续调用get_next_item中间没有item_done→ 一次只能持有1个transaction不支持预取多个。sequence不调用start_item/finish_item直接seq_item_port.put→ put是push模型sequence主动推item不是UVM默认pull模型很少用。端口方向搞反drv.seq_item_export.connect(seqr.seq_item_port)直接报错port请求方driver连 export提供方sequencer六、Pull模型 vs Push模型区分Pull模型默认sequence-seqr-driverDriver主动拉Driver是主控什么时候取激励由driver决定适合DUT有backpressure反压场景DUT忙的时候driver可以慢一点取item。Push模型sequence主动put推送给driversequence主控强制把item塞给driverdriver被动接收很少在激励通路使用。七、面试常问总结sequence和driver不直接相连中间必须经过sequencer通信端口是uvm_seq_item_pull_port标准是pull模型标准两步握手get_next_item()拿item → 驱动DUT →item_done()确认完成sequencer内置FIFO缓存transaction可以支持多个sequence并发virtual sequence

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑