- Verilog模块的端口提供了一种描述设计中模块之间连接关系的方式,但是在大型复杂的设计中,Verilog模块的端口有许多缺点。这些缺点包括:
- 在多个模块中必须重复声明端口
- 在多个模块中通信协议中也必须重复
- 在不同模块中有声明不匹配的风险
- 设计规范中的一个改动需要修改多个模块
- SystemVerilog相比Verilog增加了一种新的功能强大的端口类型:接口。
interface main_bus;
wire [15:0] data;
wire [15:0] address;
logic [7:0] slave_instruction;
...
endinterface
module tpo(input logic clock,resetN,test_mode);
logic [15:0] program_address,jump_address;
logic [7:0] instruction,next_instruction;
main_bus bus();
processor procl(
.bus(bus),
.jump_address(jump_address),
.instruction(instruction)
);
endmodule
module processo(
main_bus bus,
output logic [15:0] jump_address,
input logic [7:0] instruction
);
endmodule
- 模块端口可以声明为两种类型,显示命名的接口端口和通用接口端口。显示命名的接口端口只可以连接到同一名称的接口上,其他不同定义的接口连接到这个端口就会报错。如果端口声明是通用接口类型,那么这个端口可以连接到任何类型的接口实例上。接口的端口也可以定义为一个接口,这使得接口可以连接到另一个接口上。
interface chip_bus;
...
endinterface
module CACHE(
chip_bus pins,
input clock
);
...
endmodule
module RAM(
interface pins,
input clock
);
...
endmodule
- SystemVerilog接口定义时,可以定义接口信号的不同接入方式,在接口内部使用关键字modport来定义。如果连接到接口的模块没有指定modport,那么模块可以访问接口中定义的所有信号。
interface chip_bus(input logic clock, resetN);
logic interrupt_request,grant,ready;
logic [31:0] address;
wire [63:0] data;
modport master(
input interrupt_request,
input address,
output grant,ready,
inout data,
input clock,resetN
);
modport slave(
output interrupt_request,
output address,
input grant,ready,
inout data,
input clock,resetN
);
endinterface
- SystemVerilog提供两种方式,指定模块接口端口使用哪种modport方式。modport既可以在模块实例中指定,又可以在模块定义中指定,但不能同时选择这两种方式。如果没有在接口连接中指定modport,那么接口中所有的线网信号将默认为是双向inout信号,而所有的变量将默认为ref类型。
chip_bus bus();
primary i1(.bus(bus.master));
module primary(
chip_bus bus
);
...
endmodule
chip_bus bus();
primary i1(.bus(bus));
module primary(chip_bus.master bus);
...
endmodule
module top(input logic clock,resetN,test_mode);
logic [15:0] program_address,jump_address;
logic [7:0] instruction,next_instruction,data_b;
main_bus bus(.*);
processor procl(.bus(bus.master),.*);
slave slave1(.bus(bus.slave),.*);
instruction_reg ir(.*);
test_generator test_gen(.bus(bus),.*);
dual_port_ram ram(.bus(bus.mem),.*,.data_b(next_instruction));
endmodule
- SystemVerilog可以在接口中声明任务和函数,这些任务和函数可以作为接口方法来引用。接口的方法可以对接口中的任意信号进行操作,并可以通过输入参数从接口外部读入值,还可以通过输出参数或函数返回值将数值从接口方法写出。对于大型设计的建模,使用接口的方法有许多优势。使用接口方法,模块之间通信的细节可以转移到接口内描述。从而,与模块间通信的细节可以转移到接口内描述。如果模块通过modport连接到接口上,那么接口方法必须用关键字import指定。导入(import)定义是在接口中指定为modport定义的一部分。
modport in(
import Read,
import parity_gen,
input clock,resetN
);
modport in(
import task Read(
input [63:0] data,
output [31:0] address
),
import function parity(
input [63:0] data
),
input clock,resetN
);
interface math_bus(input logic clock,resetN);
int a_int,b_int,result_int;
real a_real,b_real,result_real;
task IntegerRead(output int a_int,b_int);
endtask
task FloatingPointRead(output real a_real,b_real);
endtask
modport int_io(
import IntegerRead,
input clock,resetN,
output result_int
);
modport fp_io(
import FloatingPointRead,
input clock,resetN,
output result_real
);
endinterface
module dual_mu(input logic clock,resetN);
math_bus bus_a;
math_bus bus_b;
integer_math_unit i1(.io(bus_a.int_io));
floatint_point_unit i2(.io(bus_b.fp_io));
endmodule
module integer_math_unit(interface io);
int a_reg,b_reg;
always@(posedge io.clk)
begin
io.IntegerRead(a_reg,b_reg);
...
end
endmodule
module floatint_point_unit(interface io);
int a_reg,b_reg;
always@(posedge io.clk)
begin
io.FloatingPointRead(a_reg,b_reg);
...
end
endmodule
- 接口可以使用参数进行向量位数和其他声明,使用Verilog的参数重定义结构对其重构,也可以使用SystemVerilog的数据类型参数化。
interface math_bus #(
parameter type DTYPE=int
) (
input logic clock
);
DTYPE a,b,result;
task Read(output DTYPE a,b);
...
endtask
modport int_io(
import Read,
input clock,
output result
);
modport fp_io(
import Read,
input clock,
output result
);
endinterface
module top(input logic clock,resetN);
math_bus bus_a(clock);
math_bus#(.DTYPE(real)) bus_b(clock);
integer_math_unit i1(.io(bus_a.int_io));
floating_point_unit i2(.io(bus_b.fp_io));
endmodule