在verilog中每当遇到复杂的模块时,我们都不得不书写一长串端口声明,
稍有不慎就会写错,并且难以检查。但在systemverilog中,接口interface
则是避免了这个问题。
下面的代码是对一个一位加法器的验证,使用了接口。
`timescale 1ns / 1psinterface if_port( input bit clk ); // 声明接口 logic a , b , cin , sum ,cout ; // 声明所有的连接线 clocking cp@(posedge clk); // 声明在同一个时钟变化下,连接线的方向。 output a , b, cin ; endclocking clocking cn@(posedge clk); input a , b , cin , sum ,cout; endclocking modport simulus(clocking cp); // 声明端口的输入与输出 modport adder( input a , b , cin , output sum ,cout ); modport monitor(clocking cn);endinterfacemodule simulus(if_port.simulus port); // 使用接口的激励模块 always@(port.cp) begin port.cp.a <= $radnom()%2 ; port.cp.b <= $random()%2 ; port.cp.cin <= $random()%2 ; endendmodule:simulusmodule adder(if_port.adder port); // 一位加法器 assign { port.cout , port.sum } = port.a + port.b + port.cin ;endmodule:addermodule monitor(if_port.monitor mon); // 监测模块,在时钟的下降沿打印结果 always@( mon.cn )begin $display(" %d %d %d %d %d ",mon.cn.a , mon.cn.b , mon.cn.cin , mon.cn.cout , mon.cn.sum ); endendmodulemodule top; timeunit 1ns ; timeprecision 1ps ; // 模块内部的时钟情况 bit clk ; if_port port(clk); // 实例化所有模块,并且连接接口 simulus sim(port.simulus); adder add(port.adder); monitor mon(port.monitor); initial begin clk <= 0 ; // 时钟的生成 while(1) #10 clk = ~clk ; end endmodule
相信由这个例子,大家可以看出接口的使用方法。尽管在这个例子中接口的使用比较繁琐,
但在一个较大型的模块中时,使用接口绝对是最佳的方式。
在接口中还有一种叫做虚接口,虚接口是接口的一个句柄,可以同过虚接口来操作接口成员的值。
下面就看看IEEE sv标准中的例子。
interface SBus; // A Simple bus interface logic req, grant; logic [7:0] addr, data;endinterfaceclass SBusTransctor; // SBus transactor class virtual SBus bus; // virtual interface of type Sbus function new( virtual SBus s ); bus = s; // initialize the virtual interface endfunction task request(); // request the bus bus.req <= 1'b1; endtask task wait_for_bus(); // wait for the bus to be granted @(posedge bus.grant); endtaskendclassmodule devA( Sbus s ) ... endmodule // devices that use SBusmodule devB( Sbus s ) ... endmodulemodule top; SBus s[1:4] (); // instantiate 4 interfaces devA a1( s[1] ); // instantiate 4 devices devB b1( s[2] ); devA a2( s[3] ); devB b2( s[4] ); initial begin SbusTransactor t[1:4]; // create 4 bus-transactors and bind t[1] = new( s[1] ); t[2] = new( s[2] ); t[3] = new( s[3] ); t[4] = new( s[4] ); // test t[1:4] endendmodule
可以看出接口与模块还是以实例化的方式相互连接,但在激励上使用了类与虚接口来进行实现。
这样在书写激励时可以动态的修改激励,并且在一定程度上增进了代码的复用程度。