UVM中如何通过modport强制使用clocking block?
UVM中通过Modport限制虚拟接口访问的标准方案
我想在验证环境中使用以下SystemVerilog特性:
- clocking block:放在接口中,避免driver与monitor之间的竞争条件
- modport:通过传递modport而非完整接口,确保只能通过clocking block访问接口信号
但在UVM环境中,我们通常实例化虚拟接口并通过config database传递。我不清楚怎么让driver只获取modport引用而非完整虚拟接口,想知道避免意外绕过modport访问信号的标准方案是什么?
我自己写了一段未验证的代码,但不确定是否是最优方案,而且发现一个问题:接口中实现的函数/任务无法被访问。
我的代码示例
interface my_interface(input clk); logic I; logic O; clocking cb_drv @(posedge clk); output I; input O; endclocking clocking cb_mon @(posedge clk); input I; output O; endclocking modport drv(clocking cb_drv, output clk); modport mon(clocking cb_mon, input clk); endinterface class my_driver extends uvm_driver #(my_transaction); `uvm_component_utils(my_driver); virtual my_interface.drv vif; // ... 其他代码 virtual function void build_phase(uvm_phase phase); virtual my_interface temp; super.build_phase(phase); if(!uvm_config_db#(virtual my_interface)::get(this, "", "my_interface", temp)) `uvm_fatal("VIF_GET", "Failed to get virtual interface"); vif = temp.drv; endfunction virtual task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(transaction); @(vif.cb_drv); vif.cb_drv.I = transaction.I; seq_item_port.item_done(); end endtask endclass
问题分析与解决方案
你的思路方向是对的:在component中声明带有modport的虚拟接口句柄,从config_db获取完整接口后转成modport类型,这确实能限制对接口信号的直接访问。但接口函数/任务无法访问的原因是你的modport没有显式包含这些方法。
标准解决方法
要解决这个问题,只需在modport定义中通过import关键字显式导入需要访问的接口函数/任务,示例如下:
修改后的接口代码
interface my_interface(input clk); logic I; logic O; // 接口内的自定义函数 function void drv_init(); cb_drv.I <= 1'b0; endfunction // 接口内的自定义任务 task drv_reset(int cycles); repeat(cycles) @(posedge clk); cb_drv.I <= 1'b0; endtask clocking cb_drv @(posedge clk); output I; input O; endclocking clocking cb_mon @(posedge clk); input I; output O; endclocking // 在modport中导入需要的函数/任务 modport drv(clocking cb_drv, output clk, import drv_init, import drv_reset); modport mon(clocking cb_mon, input clk); endinterface
修改后的driver代码(可调用接口函数)
class my_driver extends uvm_driver #(my_transaction); `uvm_component_utils(my_driver); virtual my_interface.drv vif; // ... 其他代码 virtual function void build_phase(uvm_phase phase); virtual my_interface temp; super.build_phase(phase); if(!uvm_config_db#(virtual my_interface)::get(this, "", "my_interface", temp)) `uvm_fatal("VIF_GET", "Failed to get virtual interface"); vif = temp.drv; endfunction virtual task run_phase(uvm_phase phase); // 调用接口内的初始化函数 vif.drv_init(); forever begin seq_item_port.get_next_item(transaction); @(vif.cb_drv); vif.cb_drv.I = transaction.I; seq_item_port.item_done(); end endtask endclass
核心要点总结
- 传递完整虚拟接口,转换为modport类型:从config_db获取完整虚拟接口后,赋值给带有modport的句柄,实现访问限制
- 显式导入接口方法:通过modport的
import关键字,把需要的函数/任务加入modport定义,确保component能正常调用接口提供的方法 - 严格限制信号访问:所有信号操作必须通过clocking block完成,避免直接访问接口信号,彻底消除竞争条件风险
内容的提问来源于stack exchange,提问作者G. B.
相关产品推荐
相关产品推荐

