UVM Driver中如何正确实现阻塞赋值信号到非阻塞赋值的转换?
UVM Driver中阻塞转非阻塞赋值的竞争条件问题解答
首先看你的示例代码:
task run_phase(); vif.addr <=0; forever begin seq_item_port.get_next_item(req); //@(posedge vif.CLK); Need clocking sample to avoid race condition?? vif.haddr <= req.addr; @(posedge vif.CLK iff(vif.READY)); if(req.rw == READ) begin @(posedge vif.CLK iff(vif.READY)); req.data = vif.hrdata; end else vif.hwdata <= req.data; end
核心问题分析
你当前的vif.haddr <= req.addr直接在get_next_item后执行,没有和时钟同步,确实存在竞争风险,原因如下:
req.addr是来自sequence的阻塞赋值变量,其值可能在任意时间被更新(比如sequence在时钟沿临近时修改req.addr)。- SystemVerilog的事件调度顺序中,时钟沿的采样(DUT侧
always @(posedge CLK)的信号采样)发生在预触发阶段,而非阻塞赋值的更新发生在NBA阶段。如果你的Driver在时钟沿到来前的活跃阶段执行NBA赋值,DUT在当前时钟沿采样到的会是旧值,新值要等到下一个时钟沿才会生效——这会导致协议时序不匹配,甚至出现不可预测的采样结果。
结论:必须添加时钟同步逻辑
当前写法属于易引发竞争的违规赋值,必须添加时钟采样逻辑来同步输出赋值。正确的调整方式有两种:
方式1:先等待时钟沿,再赋值
确保赋值操作在时钟沿之后执行,让新值在下一个时钟沿被DUT采样:
seq_item_port.get_next_item(req); @(posedge vif.CLK); // 先同步到时钟沿,避免时序混乱 vif.haddr <= req.addr; @(posedge vif.CLK iff(vif.READY));
方式2:将赋值与READY有效时钟沿绑定
如果你的协议要求haddr在READY有效的时钟沿被采样,可以把赋值放在该时钟沿触发后,确保DUT在下一个时钟沿能拿到稳定值:
seq_item_port.get_next_item(req); @(posedge vif.CLK iff(vif.READY)); vif.haddr <= req.addr; // 后续读/写逻辑
额外注意点
- 对于写操作的
vif.hwdata <= req.data,同样需要遵循时钟同步原则,避免直接在无时钟同步的情况下执行NBA赋值。 - 更规范的做法是在接口中使用clocking block,它会自动帮你处理时钟同步和采样/驱动的时序,从根源上避免竞争条件。
内容的提问来源于stack exchange,提问作者bu-ral
相关产品推荐
相关产品推荐

