SystemVerilog 在interface中使用modport时的例化问题

一、前言

systemverilog中有一个非常实用的功能,那就是interface。在最近写一个小练习的时候,不仅使用到了interface,还在interface中使用了modport,但是在一开始例化的时候出了点问题,所以在这里说一下需要注意的地方。

下面举一个例子,这个例子主要展示了:

  • 如何在module中调用interface
  • 如何在testbench中正确例化interfacemodule,并将在testbench中定义的与module的输入输出信号对应的信号传入module

代码功能不重要,而且我这个代码设计的有些问题,我也就不改了emmm!!!

二、举例

1、RTL代码

interface ticket_if(input logic clk,rst_n,[5:0]m_in,output logic ticket_out,[5:0]m_out);
    
    logic [5:0]sum;

    task change(input logic [5:0]in_data,
                          output logic [5:0]out_data );
                          
             out_data = in_data - 6;
    endtask //automatic

    modport ticket_ports(input clk,rst_n,m_in,
            output ticket_out,m_out,sum,
            import task change(input logic [5:0]in_data,
                               output logic [5:0]out_data )
            );
endinterface //interfacename

module ticket(ticket_if.ticket_ports ports);

enum logic [1:0]{
    
    s0,s1,s2} state_c,state_n;

always_ff @(posedge ports.clk or negedge ports.rst_n) 
     
    if(!ports.rst_n)
        state_c <= s0;
    else
        state_c <= state_n;
        
always_comb       
    case(state_c)
        s0:begin
            ports.sum = ports.m_in;
            ports.ticket_out = 0;
            if(ports.sum>=6)
                state_n <= s2;
            else
                state_n <= s1;
        end
        s1:begin
            ports.sum = ports.sum + ports.m_in;
            if(ports.sum>=6)
                state_n <= s2;
            else
                state_n <= state_c;
        end
        s2:begin
            ports.change(ports.sum,ports.m_out);
            //ports.m_out = ports.sum - 6;
            ports.ticket_out = 1;
            state_n <= s0;
        end
        default:state_n <= s0;
    endcase

endmodule

2、仿真代码

module tb_ticket;

timeunit 1ns;
timeprecision 100ps;


logic clk,rst_n;
logic [5:0]m_in;
logic ticket_out;
logic [5:0]m_out;

initial
  begin
      clk = 0;
      rst_n = '1;
      #5 rst_n = '0;
      #5 rst_n = '1;
  end
  
initial
  begin
      #10 m_in=2;
      #10 m_in=3;
      #10 m_in=4;
      #10 m_in=5;
      #10 m_in=6;
      #10 m_in=7;
      #10 m_in=8;
  end

always #5 clk = ~clk;

//ticket_if ports(.*);如果信号名称一样,你也可以直接按照这种方式来例化
ticket_if ports(.clk(clk),.rst_n(rst_n),.m_in(m_in),.ticket_out(ticket_out),.m_out(m_out));
ticket u_ticket(ports.ticket_ports);
endmodule

三、注意事项

1、需要注意的是,我们在例化的时候,只能对interface进行实例化,并不能直接对modport进行实例化。之所以这么说,是因为我们给module传入的是ticket_if.ticket_ports,这是modport类型,所以我们可能会想直接实例化一个该类型的对象,然后传给u_ticket,但是这样是行不通的。

2、于是我们只能先实例化一个interface类型的对象ports,然后将在testbench中定义的输入输出信号传给ports,之后再将modport类型的ports.ticket_ports传给module类型的对象u_ticket即可。但是这里需要注意的是,在RTL代码中,我们必须将module中使用到的输入输出信号都在interface的端口里声明一下,因为只有这样才允许在testbench中将这些信号传给ports。否则,我们就无法传递输入输出信号,那么就无法驱动待测module以完成仿真。

3、在interface的端口里声明了输入输出信号之后,我们只需要将你想要放到modport中的信号写在modport中即可。之所以使用modport,是因为一个interface可能会被多个module调用,那么如果你想要隔离开这些module之间不同的信号,你就可以像例子中那样,为每一个module添加一个modport来"包裹"只属于某个module的信号。一些共同的信号你可以放在interfacemodport外。

总之,为了能在例化的时候正确的将驱动信号传入module,你需要将这些信号在interface的端口声明一下。

猜你喜欢

转载自blog.csdn.net/qq_39507748/article/details/111058364
今日推荐