流水线式UVM中如何从Driver向Sequence传递读数据?
UVM流水线Driver向Sequence/Test传递读数据的解决方案
问题背景
在流水线式AHB UVM Driver中,已能通过req.HRDATA = ahb_if.HRDATA;读取总线读数据,但使用seq_item_port.get()获取请求后,Sequence会立即阻塞直至Driver调用put(req),无法同时维持流水线操作并等待读数据就绪,导致读数据无法正常传递回Sequence或Test。
核心解决方案:使用UVM Request/Response分离机制
UVM的seq_item_port提供了get_next_item()/item_done()的异步交互接口,专门适配流水线场景——Sequence无需阻塞等待当前请求处理完成,可继续生成后续请求,Driver处理完读操作后再异步返回响应。
1. 修正Driver的Run Phase逻辑
替换原有的get()/put()为get_next_item()/item_done(),并正确处理读数据的时序等待与响应返回:
class ahb_pipelined_driver extends uvm_driver #(ahb_seq_item); `uvm_component_utils(ahb_pipelined_driver) virtual ahb_interface ahb_if; uvm_analysis_port #(ahb_seq_item) ap; // 可选,用于广播读数据到Test function new(string name, uvm_component parent); super.new(name, parent); ap = new("ap", this); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); if(!uvm_config_db#(virtual ahb_interface)::get(this, "", "ahb_if", ahb_if)) begin `uvm_fatal(get_full_name(), "Failed to get virtual interface") end endfunction task run_phase(uvm_phase phase); ahb_seq_item req; ahb_seq_item rsp; forever begin // 获取下一个请求,Sequence无需阻塞可继续生成后续请求 seq_item_port.get_next_item(req); // 驱动AHB控制信号 ahb_if.HADDR <= req.HADDR; ahb_if.HWRITE <= req.HWRITE; ahb_if.HBURST <= req.HBURST; if(req.HWRITE) begin ahb_if.HWDATA <= req.HWDATA; end // 等待AHB读数据就绪(严格遵循协议时序:等待HREADY有效) @(posedge ahb_if.HCLK); while(!ahb_if.HREADY) begin @(posedge ahb_if.HCLK); end // 生成响应对象,关联请求ID以保证一一对应 $cast(rsp, req.clone()); rsp.set_id_info(req); rsp.HRDATA = ahb_if.HRDATA; rsp.HRESP = ahb_if.HRESP; // 发送响应并标记当前请求完成,释放Sequence继续生成请求 seq_item_port.item_done(rsp); end_tr(rsp); // 可选:通过Analysis Port广播读数据到Test或其他监听组件 ap.write(rsp); end endtask endclass
2. 在Sequence中接收响应
使用get_response()接收Driver返回的读数据,可通过fork/join_none实现流水线式的响应处理,避免阻塞请求生成:
class ahb_read_sequence extends uvm_sequence #(ahb_seq_item); `uvm_object_utils(ahb_read_sequence) function new(string name = "ahb_read_sequence"); super.new(name); endfunction task body(); ahb_seq_item req; ahb_seq_item rsp; repeat(8) begin // 生成8个流水线读请求 req = ahb_seq_item::type_id::create("req"); start_item(req); // 配置读请求 req.HWRITE = 1'b0; req.HADDR = 'h100 + (get_sequence_id() << 2); // 示例地址 req.randomize(); finish_item(req); // 异步处理响应,不阻塞下一个请求的生成 fork begin get_response(rsp); `uvm_info(get_full_name(), $sformatf("Read Addr: %h, Data: %h", rsp.HADDR, rsp.HRDATA), UVM_MEDIUM) end join_none end // 等待所有响应处理完成 wait fork; endtask endclass
3. 向Test传递读数据的额外方案:Analysis Port广播
若Test需要直接监听所有读数据(无需与Sequence请求一一绑定),可通过Driver的uvm_analysis_port实现:
- 在Test中创建订阅者组件:
class ahb_read_monitor_sub extends uvm_subscriber #(ahb_seq_item); `uvm_component_utils(ahb_read_monitor_sub) function new(string name, uvm_component parent); super.new(name, parent); endfunction function void write(ahb_seq_item t); `uvm_info("TEST_READ_MON", $sformatf("Monitored Read: Addr=%h, Data=%h", t.HADDR, t.HRDATA), UVM_LOW) endfunction endclass
- 在Test的Build Phase中实例化并连接端口:
class ahb_test extends uvm_test; `uvm_component_utils(ahb_test) ahb_env env; ahb_read_monitor_sub read_sub; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); env = ahb_env::type_id::create("env", this); read_sub = ahb_read_monitor_sub::type_id::create("read_sub", this); env.driver.ap.connect(read_sub.analysis_export); endfunction endclass
关键说明
原问题的核心原因是seq_item_port.get()为阻塞式调用,会暂停Sequence的请求生成直至Driver调用put();而get_next_item()/item_done()的组合实现了请求与响应的异步解耦,既维持了流水线的持续请求生成,又能保证读数据正确传递回Sequence。
内容的提问来源于stack exchange,提问作者bu-ral
相关产品推荐
相关产品推荐

