2. SystemVerilog 接口基础:接口定义语法、接口端口声明、模块连接方式

接口(Interface)是 SystemVerilog 相对于传统 Verilog 最重要的结构化特性之一。它将一组信号(线网、变量、任务、函数、断言)封装成一个独立的实体,使得模块之间的连接从“逐信号连线”升级为“单点绑定”。本节从语法、端口声明和模块连接三个层面建立接口的基础认知。

2.1 接口定义语法

接口使用 interface 关键字定义,内部可以包含信号声明、时钟块、断言、任务和函数。基本语法结构如下:

interface interface_name [参数列表] [modport 列表];
    // 信号声明
    logic [7:0] data;
    logic       valid;
    logic       ready;

    // 时钟块(可选)
    clocking cb @(posedge clk);
        input  data, valid;
        output ready;
    endclocking

    // 任务或函数(可选)
    task send_data(input [7:0] d);
        data = d;
        valid = 1;
        @(posedge ready);
        valid = 0;
    endtask

    // modport 定义(可选)
    modport master (input  ready, output data, valid);
    modport slave  (input  data, valid, output ready);
endinterface
语法元素说明示例
interface … endinterface定义接口的起始与结束interface bus_if;
信号声明内部信号,类型与 Verilog 一致logic [31:0] addr;
modport定义信号方向视图modport master (output addr);
clocking定义同步采样/驱动时序clocking cb @(posedge clk);
任务/函数封装协议操作task read(input addr);
要点:接口本身不包含 input/output 方向——方向由 modport 或模块连接时的端口绑定决定。接口内部的信号默认是双向的(类似 wire),方向约束通过 modport 施加。

2.2 接口端口声明

接口可以像模块一样拥有参数和端口,但接口的“端口”通常指接口内部暴露给外部的信号集合。实际使用中,接口端口声明有两种常见形式:

2.2.1 无参数接口

interface simple_if;
    logic       clk;
    logic       rst_n;
    logic [7:0] data;
    logic       valid;
endinterface

2.2.2 参数化接口

interface param_if #(parameter WIDTH = 8, parameter DEPTH = 16);
    logic             clk;
    logic             rst_n;
    logic [WIDTH-1:0] data;
    logic [$clog2(DEPTH)-1:0] addr;
    logic             wr_en;
endinterface
声明方式适用场景优点缺点
无参数接口固定位宽、固定协议简单直接,易读复用性差
参数化接口可配置位宽、深度高复用,适应不同设计参数传递需谨慎
含 modport 接口多角色连接(master/slave)方向清晰,避免误驱动定义稍复杂
常见错误:在接口内部使用 input/output 声明信号。接口内部信号应使用 logic 或 wire,方向通过 modport 或模块端口绑定来指定。直接在接口内写 input logic clk 会导致编译错误。

2.3 接口与模块的连接方式

接口与模块的连接有三种主流方式,按使用频率从高到低排列:

  1. 直接传递接口实例 —— 模块端口声明为接口类型,顶层传递接口句柄。
  2. modport 定向连接 —— 在接口实例后附加 modport 名称,指定信号方向。
  3. 接口数组连接 —— 将多个接口实例组成数组,用于总线矩阵或多通道场景。

2.3.1 直接传递接口实例

// 接口定义
interface bus_if;
    logic [31:0] addr;
    logic [31:0] data;
    logic        we;
endinterface

// 模块端口使用接口类型
module master (bus_if mif);
    // 使用 mif.addr, mif.data, mif.we
endmodule

module slave (bus_if sif);
    // 使用 sif.addr, sif.data, sif.we
endmodule

// 顶层连接
module top;
    bus_if bus_inst();
    master u_master (.mif(bus_inst));
    slave  u_slave  (.sif(bus_inst));
endmodule

2.3.2 modport 定向连接

interface bus_if;
    logic [31:0] addr;
    logic [31:0] data;
    logic        we;
    modport master (output addr, data, input we);
    modport slave  (input addr, data, output we);
endinterface

module master (bus_if.master mif);  // 使用 modport
    // mif.addr 是 output,mif.we 是 input
endmodule

module slave (bus_if.slave sif);
    // sif.addr 是 input,sif.we 是 output
endmodule

2.3.3 接口数组连接

interface channel_if;
    logic [7:0] payload;
    logic       sop, eop;
endinterface

module router (channel_if.inp ports[4]);  // 4 个输入通道
    // 使用 ports[0].payload, ports[1].sop 等
endmodule

module top;
    channel_if ch[4]();  // 声明 4 个接口实例
    router u_router (.ports(ch));
endmodule
连接方式对比总结:
  • 直接传递:最简洁,适合信号方向由模块内部逻辑保证的场景。
  • modport 连接:方向显式化,适合 master/slave 多角色复用同一接口。
  • 接口数组:适合交叉开关、路由器、多通道 DMA 等结构化设计。
接口定义与模块连接结构 接口定义与模块连接结构 interface bus_if logic [31:0] addr logic [31:0] data logic we modport master(...) modport slave(...) module master (bus_if.master mif) module slave (bus_if.slave sif) mif sif 连接要点 1. 接口实例在顶层声明(bus_if bus_inst()),不指定方向。 2. 模块端口使用接口类型 + modport 指定方向视图。 3. 所有模块共享同一接口实例,信号自动连通。 modport 方向视图与信号流 modport 方向视图与信号流 modport master output addr output data input we interface 内部 logic [31:0] addr logic [31:0] data logic we modport slave input addr input data output we 驱动 驱动 采样 采样 采样 驱动 方向视图规则 • master 的 output 信号由 master 驱动,内部信号值随之更新。 • slave 的 input 信号从内部采样,不能驱动内部信号。 • 同一信号在不同 modport 中方向可以不同,但同一时刻只能有一个驱动源。
工程建议:在验证环境中,推荐为每个协议定义独立的接口文件,并在接口内同时提供 modport 和 clocking 块。这样 driver、monitor、scoreboard 可以直接通过 modport 连接,避免信号方向错误。接口参数化后,同一个接口文件可以适配不同位宽的设计,大幅减少重复代码。