时钟声明
对于并行断言,其必须要具备时钟,property中可能具有单个时钟,也有可能是包括多个时钟。
单时钟
1.在sequence中独立指定时钟
sequence s2;
@(posedge clk) a ##2 b;
endsequence
property p2;
not s2;
endproperty
assert property(p2);
2.在property中独立指定时钟
property p2;
@(posedge clk) not (a ##2 b);
endproperty
assert property(p3);
3.在过程快中,可以继承过程块的时钟
always@(posedge clk) assert property (not(a ##2 b))
4.在时钟快中,也可以继承时钟块的时钟
clocking master_clk @(posedge clk)
property p3;
not(a ##2 b);
endproperty
endclocking
assert property(master_clk.p3);
断言时钟按照优先级逐级判定:
- 显示声明断言时钟
- 继承断言所嵌入环境的时钟
- 继承默认的时钟
多时钟
一般对sequence或者property,默认情况下,在使用同一个时钟用来对数据做采样,但是不排除有多个时钟的采样。如果一个sequence或者property需要声明多个时钟用来做数据采样,可以使用##1结合第二个时钟沿采样。
sequence中,只能使用##1来表示与第一个时钟(CLK1)沿紧密相连的下一个时钟,而sequence操作符例如and、or、intersect等无法被使用在多时钟sequence。
//以下声明均非法
sequence clk_illegal;
@(posedge clk1) s1 ##0 @(posedge clk2) s2
@(posedge clk1) s1 ##2 @(posedge clk2) s2
@(posedge clk1) s1 intersect @(posedge clk2) s2
endsequence
在property中,可以使用and、or、intersect可以在多时钟property中使用,因为它们代表逻辑运算,并不参与sequence之间的时序。
property clk_legal;
@(posedge clk1) b and @(posedge clk2) c;
endproperty
assert property (@(posedge clk0) a |=> clk_legal) else $error();
注意:
-
对于多时钟的断言,必须显示声明时钟,无法继承或者使用默认时钟;
-
多时钟断言也无法嵌套入由时钟驱动的过程语句块和时钟块中
//以下声明非法, always @(clk) assert property (mult_clock_prop);//mult_clock_prop表示为多时钟的property initial @(clk) assert property (mult_clock_prop);
绑定
断言既可以嵌入到设计中,也可以在设计外部定义。但是嵌入到设计内部,就需要考虑是否可以综合的问题,需要考虑添加编译定向。而在设计外部定义,不需要担心可综合的问题。那么如何在设计在外部定义呢?
- 采用bind方法可以满足在设计外部定义断言,将断言绑定到设计内部或者接口上面;
- bind 可以将包含断言的模块与设计模块或者实例进行绑定,既可以满足对设计信号的可视性,又能满足断言模块的独立性;
- 使用方法:bind design_block_or_instance_name block_with_assertion
- 使用绑定的优势:无需修改原有设计代码,也不需要添加监测信号,就可以实现断言的添加。
interface range(input clk,enable,input int minval,expr);
property crange_en;
@(posedge clk) enable |-> (minval <= expr);
endproperty
range_chk: assert property(crange_en);
endinterface
bind cr_unit range r1(c_clk,c_en,v_low,(in1&&in2));
注意:(以上面代码做例子)
-
r1相当于range这个interface 的实例,将DUT的端口或者内部信号与它相连;
-
但是这个接口与验证环境TB中的interface有所不同之处:
- TB中的interface想看DUT内部层次以下的信号,可以访问DUT内部层次的方式,访问内部信号,例如tb.dut.a.b.sig1。但是绑定时的接口是看不到DUT的层次,只能看到DUT的端口和这一层的内部信号,看不到层次以下的信号;
- TB中的interface在例化后,其实体是存在于TB下的;而绑定时的接口例化后的实体是放在DUT内部。
expect语句
assert、assume和cover都是非阻塞的方式,即他们本身并不去去阻塞后续的语句。而expect则是property中的一种阻塞使用方式。
- expect的使用和assert一致,不过它会等待property执行通过,才会执行后续的语句。
//仿真在200ms开始,在连续的3拍内,要依次看到a,b,c,拉高,
//那么expect语句才会通过,否则报错
initial begin
#200ms;
expect( @(posedge clk) a ##1 b ##1 c ) else $error("expect failed");
end
- expect同assert语句的调用方式类似,可以在function和task中使用,同时也可以引用静态变量或者动态变量
integer data;
...
task automatic wait_for(integer value,output bit success);
expect(@(posedge clk) ##[1:10] data==value) success = 1;
else success = 0;
endtask
initial begin
bit ok;
wiat_for(23,ok);
end