如何将带modport的SystemVerilog接口连接到未用modport声明的模块
SystemVerilog带modport的接口连接DUT正确方案
你现有代码存在3个核心错误,直接导致信号驱动失效:
- 信号作用域错误:
rst等信号定义在interface内部,tb作用域下不存在同名变量,直接写rst = 0属于无效驱动,仿真器不会识别。 - 端口连接语法错误:modport是接口信号的方向约束集合,不是实际的信号层级,连接DUT时写
intf.des.rst属于非法路径写法。 - 路径引用混淆:时钟、接口信号的驱动路径不统一,容易出现多驱动或无驱动的问题。
写法1:兼容原有DUT端口定义(无需修改DUT代码)
如果你的DUT保持传统逐信号定义的端口列表,不需要修改DUT,只需要修正tb里的连接和驱动路径即可,完整可运行代码如下:
module tb; // 时钟定义在tb层 reg clk; // 实例化接口,将tb的clk接入接口的clk端口 design_name_if intf (.clk(clk)); // DUT端口连接:直接引用接口实例下的顶层信号,不要加modport名 design_name dut ( .clk (clk), // 也可写intf.clk,二者物理连通 .rst (intf.rst), .write_addr (intf.write_addr) // 其余端口按相同规则连接intf下的同名信号即可 ); // 时钟生成:驱动tb层的clk即可,信号会同步传入接口和DUT initial begin clk = 0; forever #1 clk = ~clk; end // 复位驱动:必须加intf.前缀,指定信号属于接口实例 initial begin intf.rst = 0; #10 intf.rst = 1; end endmodule
写法2:显式使用modport做端口方向检查(推荐用于规范化验证环境)
如果要发挥modport的方向检查作用,需要将DUT的端口声明为对应modport类型,连接时可以直接传入整个modport,后续封装task/function也更方便。
第一步:修改DUT端口定义
module design_name #( parameter AWIDTH = 32, parameter DWIDTH = 32 // 其余参数保持不变 ) ( // 原逐信号端口替换为接口modport端口 design_name_if.des des_if ); // 内部逻辑引用信号时,加des_if.前缀即可,例如: // always @(posedge des_if.clk) ... // assign xxx = des_if.write_addr; endmodule
第二步:修改tb连接逻辑
module tb; reg clk; design_name_if intf (.clk(clk)); // DUT连接:直接传入接口的des modport,不需要逐信号连接 design_name dut ( .des_if (intf.des) ); // 时钟、复位驱动逻辑和写法1完全一致 initial begin clk = 0; forever #1 clk = ~clk; end initial begin intf.rst = 0; #10 intf.rst = 1; end endmodule
关键注意事项
- 永远不要在信号引用路径中加modport名(例如
intf.des.rst是错误写法),modport只用于端口声明时的方向约束,不生成新的信号层级。 - 所有interface内部的信号,在tb中驱动时必须带上接口实例的路径前缀,否则会触发变量未定义错误,导致驱动失效。
- 时钟信号只需要在一个位置驱动即可,要么驱动tb层的clk(通过端口传入接口),要么把clk定义为interface内部信号直接驱动
intf.clk,禁止多源驱动。
内容的提问来源于stack exchange,提问作者joshgalv
相关产品推荐
相关产品推荐

