Title

SystemVerilog -- 6.3 Interface ~ Modports

在接口中定义带有方向的modport列表,以对模块内的接口访问施加某些限制。关键字指示方向的声明方式与模块内部一样。

Syntax

modport [identifer] (
    input  [port_list],
    output [port_list]
);

下面显示的是接口myInterface的定义,它有几个信号和两个声明。modportdut0本质上声明信号acksel是输入,gntirq0是使用此特定modport的任何模块的输出。

类似地,声明了另一个名为dut1的modport,它声明gntirq0是输入,另外两个是任何使用modportdut1的模块的输出。

interface myInterface;
    logic ack;
    logic gnt;
    logic sel;
    logic irq0;

    // ack and sel are inputs to the dut0, while gnt and irq0 are outputs
    modport dut0 (
      input  ack, sel,
      output gnt, irq0
    );

    // ack and sel are outputs from dut1, while gnt and irq0 are inputs
    modport dut1 (
      input  gnt, irq0,
      output ack, sel
    );
endinterface

Example of named port bundle

在这种风格中,设计将从接口对象中获取所需的正确modport定义,如其端口列表中所述。tb只需要为设计提供整个接口对象。

module dut0 (myInterface.dut0 _if);
    ...
endmodule

module dut1 (myInterface.dut1 _if);
    ...
endmodule

module tb;
    myInterface    _if;
    dut0 d0  ( .* );
    dut1 d1  ( .* );
endmodule

Example of connecting port bundle

在这种风格中,设计只是接受任何方向信息。因此,tb负责为设计提供正确的modport值。

module dut0 (myInterface _if);
    ...
endmodule

module dut1 (myInterface _if);
    ...
endmodule

module tb;
    myInterface  _if;
    dut0 d0 (._if(_if.dut0));
    dut1 d1 (._if(_if.dut1));
endmodule

What is the need for a modport ?

默认情况下,简单接口中声明的是net,因此连接到同一net的任何模块都可以驱动或从中获取值。简单来说,对数据传播的方向没有限制。你最终可能会在net上得到一个x,因为tb和设计都将两个不同的值驱动到一个接口net。tb编写者应特别小心,以确保不会发生这种情况。这可以通过使用modport从本质上避免。inout

Example of connecting to generic interface

A还可以将通用接口用作端口列表。通用句柄可以接受从上面的层次结构传递给它的任何modport。

module dut0 (interface _if);
    ...
endmodule

module dut1 (interface _if);
    ...
endmodule

module tb;
  myInterface   _if;
  dut0    d0 (._if (_if.dut0));
  dut1    d1 (._if (_if.dut1));
endmodule

Design Example

让我们考虑两个模块主从模块通过一个非常简单的总线结构连接。假设总线能够发送一个地址和数据,slave应该捕获并更新其内部寄存器中的信息。因此,master始终必须启动传输,并且从站能够通过sready信号向master指示它是否准备好接受数据。

Interface

下面显示的是master和slave之间共享的定义。

interface ms_if (input clk);
    logic       sready;
    logic       rstn;
    logic [1:0] addr;
    logic [7:0] data;

    modport slave  (input addr, data, rstn, clk,
                    output sready);

    modport master (output addr, data,
                    input clk, sready, rstn);
endinterface

RTL Design

假设主节点只是将地址从0迭代到3,并发送等于地址乘以4的数据。master应该只在slave准备好接受并由sready信号指示时发送。

// This module accepts an interface with modport "master"
// master sends transactions in a pipelined format
// CLK    1   2   3   4   5   6
// ADDR   A0  A1  A2  A3  A0  A1
// DATA       D0  D1  D2  D3  D4
module master (ms_if.master mif);
    always @(posedge mif.clk) begin
      // If reset is applied, set addr and data to default values
      if (!mif.rst) begin
        mif.addr <= 0;
        mif.data <= 0;

      // Else increment addr, and assign data accordingly if slave is ready
      end else begin
      // Send new addr and data only if slave is ready
        if (mif.sready) begin
          mif.addr <= mif.addr + 1;
          mif.data <= mif.addr * 4;
        // Else maintain curent addr and data
        end else begin
          mif.addr <= mid.addr;
          mif.data <= mif.data;
        end
      end

    end
endmodule

假设slave接受每个加法器的数据,并将它们分配给内存寄存器,当地址从3换行到0时,slave需要1个额外的时钟才能准备就绪。

module slave (ms_if.slave sif);
   reg [7:0] reg_a;
   reg [7:0] reg_b;
   reg       reg_c;
   reg [3:0] reg_d;

   reg       dly;
   reg [3:0] addr_dly;

   always @(posedge sif.clk) begin
      if (!sif.rstn) begin
          addr_dly <= 0;
      end else begin
          addr_dly <= sif.addr;
      end
  end

    always @(!sif.rstn) begin
      if (!sif.rstn) begin
        reg_a <= 0;
        reg_b <= 0;
        reg_c <= 0;
        reg_d <= 0;
      end else begin
        case (addr_dly)
          0 : reg_a <= sif.data;
          1 : reg_b <= sif.data;
          2 : reg_c <= sif.data;
          3 : reg_d <= sif.data;
        endcase
      end
    end

    assign sif.sready = ~(sif.addr[1] & sif.addr[0]) | ~dly;

    always @ (posedge sif.clk) begin
       if (!sif.rstn) 
          dly <= 1;
       else
          dly <= sif.sready;
    end
endmodule

这两个设计模块在顶层捆绑在一起。

module d_top (ms_if tif);
    // Pass the "master" modport to master
    master m0 (tif.master);
    // Pass the "slave" modport to slave
    slave s0 (tif.slave);
endmodule

Testbench

testbench会将接口句柄传递给设计,然后设计将masterslave分配给其子模块。

module tb;
    reg clk;
    always #10 clk = ~clk;

    ms_if  if0 (clk);
    d_top  d0  (if0);

    initial begin
      clk <= 0;
      if0.rstn <= 0;
      repeat (5) @ (posedge clk);
      if0.rstn <= 1;
      repeat (20) @ (posedge clk);
      $finish;
    end
endmoule

请记住,master发起总线事务,slave捕获数据并将其存储在相应地址的内部寄存器reg_*中。

posted on 2024-04-26 17:50  松—松  阅读(171)  评论(0编辑  收藏  举报

导航