前言
大型IC设计中,模块中信号数量众多,不仅使用和修改麻烦,而且很难保证在信号连接中不出问题,因此systemverlog中interface出现啦!
既然写端口信号十分麻烦,那就单独为信号创建一个interface模块,然后在其他模块中例化,一旦信号名称和数量需要修改,也不必在顶层修改,只需要修改interface模块就可以。
理解interface,重点在interface只涉及模块之间共有的信号,独有的信号是没有的!
例程
下面是一个例程,方便理解interface使用方法(本例程来自一篇博客,清晰明了,稍作修改,链接在文末)
//top module
module demo_sv (
input i_clk ,
input i_rst_n ,
input i_a ,
output o_b
);
f_bus1 inst_f_bus1 ( //模块也可以写成 f_bus1 inst_f_bus1 (i_clk,i_rst_n);但是这种写法要注意名字顺序
.i_clk (i_clk),
.i_rst_n (i_rst_n)
);
genafic inst_genafic (
.f_bus1 (inst_f_bus1.master),
.i_a (i_a)
);
test inst_test (
.f_bus1 (inst_f_bus1.slave),
.o_b (o_b)
);
endmodule
//interface 子模块
interface f_bus1(input logic i_clk,i_rst_n);
logic l_ready;
logic l_valid;
logic [7:0] l_cnt;
modport master(input i_clk,i_rst_n,
output l_ready,l_valid,l_cnt);
modport slave (input i_clk,i_rst_n,
input l_ready,l_valid,l_cnt);
endinterface //f_bus1
// genafic 子模块
module genafic (
interface f_bus1, //也可以写成 f_bus1.mater f_bus1
input i_a
);
logic [7:0] l_cnt = '0;
always_ff @(posedge f_bus1.i_clk)
begin
if (f_bus1.i_rst_n)
l_cnt <= '0;
else if (i_a)
l_cnt <= l_cnt + 'd1;
end
assign f_bus1.l_ready = l_cnt[0];
assign f_bus1.l_valid = l_cnt[1];
assign f_bus1.l_cnt = l_cnt;
endmodule:genafic
//test 子模块
module test (
interface f_bus1, //也可以写成 f_bus1.slave f_bus1
output o_b
);
logic l_b = '0;
always_ff @(posedge f_bus1.i_clk)
begin
if (f_bus1.i_rst_n)
l_b <= '0;
else if (!f_bus1.l_ready && f_bus1.l_valid)
begin
if (f_bus1.l_cnt == 'd10)
l_b <= 1'b1;
else
l_b <= 1'b0;
end
end
assign o_b = l_b;
endmodule:test
例程二 ,模块不完整,仅用开来介绍模块例化时,端口信号写法
module tb;
wr_if m_wr_if(); //没有输入量
dut m_dut(m_wr_if); // 接口信号简化写法
reg clk_tb,rst_n;
logic[31:0]addr,data;
logic valid ,ready;
assign m_wr_if.clk = clk_tb;
assign m_wr_if.rst_n = rst_n;
initial
begin
clk_tb = 0;
forever
# 5 clk_tb = ~clk_tb;
end
initial
begin
rst_n = 1;
repeat(2)@(m_wr_if.cb);
#2ns
rst_n = 0;
repeat(2)@(m_wr_if.cb);
#2ns
rst_n = 1;
end
endmodule:tb
module dut(wr_if m_if); // m_if 可以不与tb中接口例化时名称m_wr_if相同,类似形参与实参
reg[31:0]wr_ready;
reg wr_ready;
assign wr_ready = 1;
assign m_if.wr_ready=1;
always@(posedge m_if.clk ,negedge m_if.rst_n)
begin
if(m_if.rst_n == 1'b0)
begin
foreach (reg_map[i])
reg_map[i] = 0;
end
else if(m_if.wr_valid && wr_ready)
begin
reg_map[m_if.wr_addr%10] = m_if.wr_data;
$display("@ %0t ns, wr data[%0d] = 'h%h", $time,m_if.wr_addr%10,m_if.wr_data);
end
end
endmodule:dut
interface wr_if();
logic clk;
logic rst_n;
logic[31:0] wr_addr;
logic[31:0]wr_data;
logic wr_valid;
logic wr_ready;
clocking cb @(posedge clk);
default input #1ns output #1ns;
output wr_addr;
output wr_data;
output wr_valid;
input wr_ready;
endclocking
endinterface :wr_if