4.2 接口
例4.4 仲裁器的简单接口
interface arb_if(input bit clk);
logic [1:0] grant,request;
logic rst;
endinterface
例4.5 使用了简单接口的仲裁器
module arb (arb_if arbif);
...
always@(posedge arbif.clk or posedge arbif.rst)
begin
if(arbif.rst)
arbif.grant<=2'b00;
else
arbif.grant<=next_grant;
...
end
endmodule
接口信号必须使用非阻塞赋值来驱动。
例4.6 使用简单仲裁器接口的测试平台
module test (arb_if arbif)
...
initial begin
...
@(posedge arbif.clk);
arbif.request<=2'b01;
$display("@%0t:Drove req=01",$time);
repeat(2)@(posedge arbif.clk);
if (arbif.grant!=2'b01)
$display("@%0t: a1: grant!=2'b01",$time);
$finish
end
endmodule:test
例4.7 使用简单仲裁器接口的top模块
module top;
bit clk;
always #5 clk=~clk;
arb_if arbif(clk);
arb a1(arbif);
test t1(arbif);
endmodule:top
4.2.3 使用modport将接口中的信号分组
例4.10 带有modport的接口
interface arb_if(input bit clk);
logic[1:0] grant,request;
logic rst;
modport TEST(output request, rst, input grant, clk);
modport DUT(input request,rst,clk,output grant);
modport MONITOR(input request,grant,rst,clk);
endinterface
例4.11 接口中使用modport的仲裁器模型
module arb(arb_if.DUT arbif);
...
endmodule
例4.12 接口中使用modport的测试平台
module test(arb_if.TEST arb_if);
...
endmodule
例4.13 接口使用modport的仲裁器监视模型
module monitor (arb_if.MONITOR arbif)
always@(posedge arbif.request[0]) begin
$display("@%0t:request[0] asserted",$time);
@(posedge arbif.grant[0]);
$display("@%0t:grant[0] asserted",$time);
end
always@(posedge arbif.request[1]) begin
$display("@%0t:request[1] asserted",$time);
@(posedge arbif.grant[1]);
$display("@%0t:grant[1] asserted",$time);
end
endmodule
4.3 激励时序
4.3.1 使用时钟块控制同步信号的时序
例4.14 带时钟块的接口
interface arb_if(input bit clk);
logic[1:0] grant,request;
logic rst;
clocking cb@(posedge clk); //声明cb
output request;
input grant;
endclocking
modport TEST(clocking cb,output rst);
modport DUT(input request,rst,output grant);
endinterface
module test(arb_if.TEST arbif)
initial begin
arbif.cb.request<=0;
@arbif.cb;
$display("@%0t:Grant=%b",$time,arbif.cb.grant);
endmodule:test
4.3.2 接口中的logic和wire对比
VMM注重代码的可重用性,其规则指明将接口中的信号定义为wire。
但本书注重logic的易用性,建议在接口中将信号定义为logic。
若要在接口中使用过程赋值语句驱动一个异步信号,则该信号必须定义为logic。
而wire变量只能被连续赋值语句驱动。
时钟块中的信号始终是同步的,可以定义为logic或者wire。
例4.15 如何驱动接口中的logic和wire信号:logic信号可以直接被驱动,wire需要使用额外的代码。
interface asynch_if();
logic l;
wire w;
endinterface
module test(asynch_if ifc);
logic local_wire;
assign ifc.w=logic_wire;
initial begin
ifc.l<=0; //直接驱动异步logic信号
local_wire<=1;// 只能用assign驱动wire信号
...
end
endmodule
4.3.4 测试平台—设计间的竞争状态
例4.14 设计和测试平台之间的竞争状态
module memory(input wire start, write,
input wire [7:0] daar,
inout wire [7:0] data);
logic [7:0] men[256];
always @(posedge start) begin
if(write)
mem[addr]<=data;
...
end
endmodule
module test(output logic start,write,
output logic [7:0] addr,data);
initial begin
start=0;
write=0;
#10;
addr=8'h42;
data=8'h5a;
start=1;
write=1;
...
end
endmodule
4.3.5 程序块(Program Block)和时序区域(Timing Region)
测试平台和设计的竞争问题的根源在于设计和测试平台的事件(event)混合在同一个时间片(time slot)内,即使在纯RTL程序中也会发生同样的问题。
在SV中,测试平台的代码在一个 程序块中。
模块中含有代码和变量,可以在其他模块中例化。
程序块不能有任何的层次级别,如模块的实例、接口或者其他程序。
SV引入了新的时间片的划分方式:
- Active(design)区域:仿真模块中的设计代码。在这个区域中运行设计事件,包括RTL、门级代码和始终发生器(clock generator)。
- Observed(assertions)区域:执行断言。
- Reactive(testbench)区域:执行程序中的测试平台部分。
- Postponed(sample)区域:为测试平台的输入采样信号。
Observed(assertions)和Reactive(testbench)区域可以触发本时钟周期内Active区域中进一步的设计事件。
例4.17 带有时钟块接口的测试平台
program automatic test(arb_if.TEST arbif);
...
initial begin
arbif.cb.request<=2'b01;
$display("@%0t:Drove req=01",$time);
repeat(2) @arbif.cb;
if(arbif.cb.grant!=2'b01)
$display("@%0t:a1:grant!=2'b01",$time);
end
endprogram:test
4.4 接口的驱动和采样
在时钟块中应当使用同步驱动,即“<=”操作符来驱动信号。
在SV中的program块中,可以使用initial块,但不可以使用always块。
不应该把时钟发生器放在程序块中,这回引起信号的竞争。应该把它放到模块中。
4.6 顶层作用域
Verilog:宏定义
SV:编译单元
任何module,macromodule,interface,program,package或者primitive边界之外的作用域被称为编译单元作用域,也称为$unit。
这个作用域内的任何成员,比如parameter,都类似于全局成员,可以被所有低一级的块访问。
$root
4.7 模块交互
4.8 SystemVerilog断言
4.8.1 立即断言
例4.33 使用if语句检查一个信号
bus.cb.request<=1;
repeat(2) @bus.cb;
if(bus.cb.grant!=2'b01)
$display("Error,grant!=1");
例4.34 简单的立即断言
bus.cb.request<=1;
repeat(2)@bus.cb;
a1:assert(bus.cb.grant==2'b01);
4.8.2 定制断言行为
立即断言有可选的then和else分句。
例4.36 在立即断言中创建一个定制的错误消息
a1:assert(bus.cb.grant==2'b01)
else $error("Grant not asserted");
SV有四个输出消息的函数:$info,$warning,$error,$fatal,仅允许在断言内部使用,而不允许在过程代码中使用。
例4.38 创建一个定制的错误消息
a1:assert(bus.cb.grant==2'b01)
grants_received++;
else
$error("Grant not asserted");
4.8.3 并发断言
例4.39 检查X/Z的并发断言
interface arb_if(input bit clk);
logic [1:0] grant,request;
logic rst;
property request_2state;
@(posedge clk) disable iff (rst);
$isunknown(request)==0;
endproperty
assert_request_2state:assert property(request_2state);
endinterface