一、前言
在systemverilog
中有一个非常实用的功能,那就是interface
。在最近写一个小练习的时候,不仅使用到了interface
,还在interface
中使用了modport
,但是在一开始例化的时候出了点问题,所以在这里说一下需要注意的地方。
下面举一个例子,这个例子主要展示了:
- 如何在
module
中调用interface
- 如何在
testbench
中正确例化interface
和module
,并将在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
的信号。一些共同的信号你可以放在interface
内modport
外。
总之,为了能在例化的时候正确的将驱动信号传入module
,你需要将这些信号在interface
的端口声明一下。