Systemverilog 接口 interface modport使用说明

一、接口的定义
     SystemVerilog在Verilog语言基础上扩展了“接口”(interface)结构,SystemVerilog增加了新的端口类型—接口,接口允许许多信号合成一组由一个端口表示,只需在一个地方对组成接口的信号进行声明,使用这些信号的模块只需一个接口类型的端口。
        接口声明举例:main_bus.sv


interface main_bus;
    wire [15:0] data;
    wire [15:0] address;
    logic [ 7:0] slave_instr;
    logic slave_req;
    logic bus_grant;
    logic bus_req;
    logic slave_rdy;
    logic data_rdy;
    logic mem_read;
    logic mem_write;
endinterface

        在顶层模块中例化接口:top.sv

module top (input logic clock, resetn, test_mode);
    logic [15:0] program_addr, jump_addr;
    logic [ 7:0] instr, next_instr;
    main_bus bus ( );  // instance of an interface
// (instance name is bus)

    processor proc1 (
// main_bus ports
        .bus(bus), // interface connection
// other ports
        .jump_addr (jump_addr),
        .instr (instr),
        .clock(clock),
        .resetn(resetn),
        .test_mode(test_mode));

 slave slave1 (
// main_bus ports
        .bus(bus), // interface connection
// other ports
        .clock(clock),
        .resetn(resetn));

    dual_port_ram ram (
// main_bus ports
        .bus(bus), // interface connection
// other ports
        .program_addr (program_addr),
        .data_b(next_instr));

endmodule

二、接口的内容
        接口不仅仅是一组连接线,它也可以封装模块间通信的所有细节。使用接口可以:(1)在一个地方—接口中定义通信所需的各个信号和端口;(2)在接口中定义通信协议;(3)在接口中直接建立协议校验和其它验证程序。
        接口可以包含类型声明、任务、函数、过程块、程序块和断言

        接口与模块之间有三个不同点:
         (1)接口不可以包含设计层次,接口不可以包含模块或原语的实例
         (2) 接口可以用作模块端口,表示模块间的通信通道,而在端口中使用模块则是非法的
         (3)接口可以包含“modport”,这使得每个连接到接口上的模块以不同的方式访问接口。          (4) 接口内部信号的使用,在有接口类型端口的模块中,接口内部信号必须用端口名进行访问:<端口名称>.<接口内部信号名称>


//接口声明
interface main_bus;
    wire [15:0] data;
    wire [15:0] address;
    logic [ 7:0] slave_instr;
    logic slave_req;
    logic bus_grant;
    logic bus_req;
    logic slave_rdy;
    logic data_rdy;
    logic mem_read;
    logic mem_write;
endinterface

//接口信号调用
module slave ( main_bus bus);
// internal signals
  logic [15:0] slave_data, slave_addr;
  logic [15:0] operand_A, operand_B;
  logic mem_select, read, write;
  
  //assign bus.address=mem_select ? slave_addr :'z;
  
  assign bus.address = mem_select? slave_addr: 'z;
  assign bus.data = bus.slave_rdy? slave_data: 'z;
 

 enum logic [4:0] {RESET = 5'b00001, START = 5'b00010,
   REQ_DATA = 5'b00100, EXECUTE = 5'b01000,
   DONE = 5'b10000} State, NextState;
   
   
  always_ff @(posedge bus.clock, negedge bus.resetn)
   begin: FSM
        if (!bus.resetn) State <= START;
        else State <= NextState;
    end
   always_comb begin : FSM_decode
        unique case (State)
            START: if (!bus.slave_req) begin
                bus.bus_req = 0;
                NextState = State;
            end
            else begin
                operand_A = bus.data;
                slave_addr = bus.address;
                bus.bus_req = 1;
                NextState = REQ_DATA;
            end
	// decode other states
        endcase
    end: FSM_decode
endmodule

接口的modport

 SystemVerilog提供两种方法指定模块接口端口使用modport的方式:
 (1)
在模块实例化时的接口连接中说明
 (2)
在模块定义的端口声明时说明;

  在模块实例化时的接口连接中说明


interface chip_bus (input logic clock, resetn);
    logic interrupt_req, grant, ready;
    logic [31:0] address;
    wire [63:0] data;
    modport master (input interrupt_req,
        input address,
        output grant, ready,
        inout data,
        input clock, resetn);
    modport slave (output interrupt_req,
        output address,
        input grant, ready,
        inout data,
        input clock, resetn);
endinterface

//
module primary (interface pins); // generic interface port

endmodule
module secondary (chip_bus pins); // specific interface port

endmodule

module chip (input logic clock, resetn);
chip_bus bus (clock, resetn); // instance of an interface
primary i1 (bus.master);  // use the master modport view
secondary i2 (bus.slave); // use the slave modport view
endmodule

在modport既可在模块实例化时指定,又可以在模块定义中指定,但不能同时选择这两种方式!!
 模块定义的端口声明时说明;

module primary (chip_bus.master pins); // generic interface port
...
endmodule
module secondary (chip_bus.slave pins); // specific interface port
...
endmodule
module chip (input logic clock, resetn);
chip_bus bus (clock, resetn); // instance of an interface
primary i1 (bus); // use the master modport view
secondary i2 (bus); // use the slave modport view
endmodule

三、interface 一主一从结构间的读写操作

 这一部分主要是interface的实际应用,在总线上挂有一主一从结构,主机对从机进行读写操作,使用modport的接口方式,同时博主也对于自己在撰写过程中遇见的错误进行了总结。
Systemverilog 接口 interface modport使用说明_第1张图片

接口部分:

//需要输入的信号 一定要在接口端口声明,否则无法传递数值
interface zuoye_interface(input logic CLK,
          input logic RESETN,
          input [31:0] wdata,         
          input [31:0] waddr,
          input [31:0] raddr);
 
logic [31:0] WDATA;
logic [31:0] RDATA;
logic [31:0] rdata;
logic [31:0] WADDR;
logic [31:0] RADDR;
logic WRITE_REQ;
logic WRITE_ACK;
logic READ_ACK;
logic READ_REQ;
logic WR_DONE;
logic RD_DONE;

//主机master
modport M1(
             input CLK,
             input RESETN,
             input WRITE_ACK,
             input READ_ACK,
             input RD_DONE,
             input wdata,
             input RDATA,
             input waddr,
             input raddr,
             output WDATA,
             output rdata,
             output WRITE_REQ,
             output WADDR,
             output RADDR,
             output READ_REQ,
             output WR_DONE
);

//从机slave
modport S1(
            input WR_DONE,
            input CLK,
            input RESETN,
            input WDATA,
            input WADDR,
            input RADDR,
            input WRITE_REQ,
            input READ_REQ,
            output RDATA,
            output READ_ACK,
            output WRITE_ACK,
            output RD_DONE
);
endinterface

TOP模块部分

module zuoye_top(input CLK,RESETN);
   zuoye_interface u1(.CLK,.RESETN);
   zuoye_M1 i1(u1.M1);
   zuoye_S1 i2(u1.S1);
endmodule

主机Master部分
 

module zuoye_M1(zuoye_interface.M1 M1);
enum logic [2:0] 
{IDLE,WAIT,WRITE_ADDR,WRITE_DATA,
STOP,READ_ADDR,READ_DATA}State,NextState;
logic [1:0] wr_flag;
always_ff @(posedge M1.CLK , negedge M1.RESETN)
begin
  if(!M1.RESETN)
    State <= IDLE;
  else
    State <= NextState;
end
always_comb
begin
 NextState=State;
unique case(State) 
  IDLE: begin
   if(wr_flag==1) 
     NextState=READ_ADDR;
   else
     NextState=WAIT;
   end 
  WAIT: begin
        if(M1.WRITE_ACK==1)
          NextState=WRITE_ADDR;
  end
  
  WRITE_ADDR:begin
    NextState=WRITE_DATA;
  end
  
  WRITE_DATA:begin
   NextState=IDLE;
  end
  
  READ_ADDR:begin
    if(M1.RD_DONE==1)
    NextState=READ_DATA;
  end
  
  READ_DATA:begin
    NextState=STOP;
  end
  
  STOP:begin
    NextState=IDLE;
  end
 endcase
end

always_ff@(posedge M1.CLK , negedge M1.RESETN)
begin
  // wr_flag <=0;
  wr_flag <=0;
  M1.WR_DONE <=0;
 unique case(State)
  IDLE: begin
    if(wr_flag==1) begin
     M1.READ_REQ  <=1;
     M1.WRITE_REQ <=0;
     end
    else begin
     M1.WRITE_REQ <=1;
     M1.READ_REQ  <=0;
     end
    end
  WAIT: begin
     ;
    end
       
  WRITE_ADDR: begin
     M1.WADDR <=M1.waddr;
   end
  WRITE_DATA: begin
    M1.WDATA  <=M1.wdata;
    wr_flag   <=1;
    M1.WR_DONE   <=1;
    end
  
  READ_ADDR: begin
    M1.RADDR <=M1.raddr;
    end
  
  READ_DATA:begin
    M1.rdata <=M1.RDATA;
    end
  
  
  STOP: begin
   ;
  end
 endcase
end

endmodule

从机slave部分

module zuoye_S1(zuoye_interface.S1 S1);
enum logic [2:0] 
{IDLE,WAIT,WRITE,STOP,READ}State,NextState;
logic [1:0] flag; //write finish
logic [7:0] array [0:255];  //memory


always_ff @(posedge S1.CLK , negedge S1.RESETN)
begin
  if(!S1.RESETN)
    State <= IDLE;
  else
    State <= NextState;
end
  
  
always_comb
begin
 NextState=State;       //初始化
unique case(State) 
  IDLE: 
    begin
     if(flag==1)
      NextState=READ;
     else
      NextState=WAIT;
    end
  
  WAIT: begin
        if(S1.WRITE_REQ==1&&S1.WR_DONE==1)
          NextState=WRITE;
        else if(S1.READ_REQ==1)
          NextState=READ;
        else
          NextState=WAIT;
  end
  
  WRITE:begin
        NextState=IDLE;
   end
  
  READ:begin
       NextState=STOP;
  end
  
  STOP:begin
    NextState=IDLE;
  end
 endcase
end
  
always_ff@(posedge S1.CLK , negedge S1.RESETN)
begin
  flag <=0;
  S1.RD_DONE <=0;
 unique case(State)
  IDLE: begin
     ;
    end
  WAIT: begin
     if(S1.WRITE_REQ==1)
         S1.WRITE_ACK <= 1; 
     else if(S1.READ_REQ==1)
         S1.READ_ACK  <= 1;
     end
       
  WRITE: begin
    array[S1.WADDR] <= S1.WDATA;
    flag <=1;
   end
  
  READ: begin
     S1.RDATA <= array[S1.RADDR];
     S1.RD_DONE  <= 1;
    end
  
  
  STOP: begin
   ;
  end
 endcase
end
endmodule

 测试代码

module zuoye_top_tb;
logic CLK,RESETN;
logic [31:0] waddr,raddr;
logic [31:0] wdata;
zuoye_interface bus(.CLK(CLK),.RESETN(RESETN),
.wdata(wdata),.waddr(waddr),.raddr(raddr));
  zuoye_M1 u_M1(bus.M1);
  zuoye_S1 u_S1(bus.S1);
initial
  begin
   CLK=0;
  forever #5 CLK=~CLK;
  end

initial
begin
   RESETN=1;
#10
   RESETN=0;
#10
   RESETN=1;
end

initial
begin
  wdata=32'h8000_0000;
  waddr=32'h8000_0000;
#50;
for(int i=0;i<32;i++)
begin
   waddr=i;
   wdata=i;
 #120;
end

for(int j=0;j<32;j++)
begin
   raddr=j;
 #120;
 end
 $finish;
end
endmodule


 

你可能感兴趣的:(Systemverilog,fpga开发)