16.16Clock resolution
有很多种方法可以指定属性里面时钟,如下所示:
(1)带时钟的序列实例,如:
sequence s2;
@(posedge clk) a ##2 b;
endsequence
property p2;
not s2;
endproperty
assert property (p2);
这是很完整的一种写法。
(2)属性:
property p3;
@(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);
(5)默认块:
default clocking master_clk ; // master clock as defined above
property p4;
(a ##2 b);
endproperty
assert property (p4);
定义全局默认时钟,在复杂代码中可以减少代码数量。
通常,时钟事件适用于其整个范围,除非被内部时钟事件取代,如多时钟序列和属性中的时钟流。下面这些规则适用:
(1)在有默认时钟事件的模块、接口、程序、检查中,没有其他指定前导时钟事件的并发断言语句,被视为默认时钟事件明确写入前导时钟事件,默认时钟事件不适用于序列或属性声明,除非声明出现在时钟事件为默认值的时钟块中。
(2)下面的规则适用于时钟块:
a、在时钟块的任何时属性或序列声明,不允许明确时钟事件,时钟块内的所有序列和属性声明,都被视为时钟块的时钟事件,已被明确写入为前导时钟事件;
b、时钟块内不允许多时钟序列和属性;
c、如果在时钟块外声明的已命名序列或属性在时钟块内实例化,则该实例应有单独的时钟,其时钟事件应与时钟块的相同。
(3)程序块根据上下文推断得到的时钟事件取代默认时钟事件,根据上下文推断得到的时钟事件,被视为已被写入推断时钟所应用的任何并发断言语句的前导时钟事件(好绕好绕-_-),这类并发断言语句的最大属性应为单时钟;
(4)并发断言语句中明确指明的前导时钟事件将取代默认时钟事件;
(5)多时钟序列或属性会继承默认时钟事件作为其前导时钟事件,如果多时钟属性是并发断言语句的最大属性,则该属性应具有唯一的语义前导时钟;
(6)如果并发断言语句没有明确时钟事件,没有默认时钟事件,且没有上下文推断时钟事件应用于断言语句,则断言语句的最大属性应为确定唯一前导时钟事件的序列或属性的实例。
下面两个例子说明这些规则在一些合法和非合法声明中的应用:
module examples_with_default (input logic a, b, c, clk);
property q1;
$rose(a) |-> ##[1:5] b;
endproperty
property q2;
@(posedge clk) q1;
endproperty
default clocking posedge_clk @(posedge clk);//定义全局时钟,默认为posedge clk
property q3;
$fell(c) |=> q1; // 合法: q1 没有时钟事件(没有定义时钟)
endproperty
property q4;
$fell(c) |=> q2; // 合法: q2具有与时钟块相同的时钟事件(两个时钟都为posedge clk)
endproperty
sequence s1;
@(posedge clk) b[*3]; // 非法: 时钟块中有明确时钟事件
endsequence
endclocking
property q5;
@(negedge clk) b[*3] |=> !b;
endproperty
always @(negedge clk)
begin
a1: assert property ($fell(c) |=> q1);
// 合法: 根据上下文推断的前导时钟事件为 @(negedge clk)
//(p1没有定义时钟,在这个always块内是negedge clk)
a2: assert property (posedge_clk.q4);
// 合法:将在negedge clk上排队(等待),然后(如果成熟)在下一个posedge clk上检查。
a3: assert property ($fell(c) |=> q2);
// 非法: 上下文推断前导时钟事件存在多个时钟
a4: assert property (q5);
// 合法: 上下文推断的前导时钟事件是@(posedge clk)
end
property q6;
q1 and q5;
endproperty
a5: assert property (q6);
// 非法: 默认前导时钟事件是 @(posedge clk),但语义前导时钟不唯一
a6: assert property ($fell(c) |=> q6);
// 合法: 默认前导时钟事件为 @(posedge clk),是唯一语义前导时钟
sequence s2;
$rose(a) ##[1:5] b;
endsequence
c1: cover property (s2);
// 合法: 默认前导时钟事件为 @(posedge clk)
c2: cover property (@(negedge clk) s2);
// 合法: 明确前导时钟事件为 @(negedge clk)
endmodule
module examples_without_default (input logic a, b, c, clk);
property q1;
$rose(a) |-> ##[1:5] b;
endproperty
property q5;
@(negedge clk) b[*3] |=> !b;
endproperty
property q6;
q1 and q5;
endproperty
a5: assert property (q6);
// 非法: 没有前导时钟事件
a6: assert property ($fell(c) |=> q6);
// 非法: 没有前导时钟事件
sequence s2;
$rose(a) ##[1:5] b;
endsequence
c1: cover property (s2);
// 非法: 没有前导时钟事件
c2: cover property (@(negedge clk) s2);
// 合法: 明确前导时钟事件为, @(negedge clk)
sequence s3;
@(negedge clk) s2;
endsequence
c3: cover property (s3);
// 合法: 根据s3的声明确定前导时钟事件为, @(negedge clk),
c4: cover property (s3 ##1 b);
// 非法: 没有默认、推断、明确的前导时钟事件,且最大属性不是一个实例
endmodule
1、多时钟序列和属性的语义前导时钟
s,s1,s2表示无时钟事件序列;p,p1,p2表示无时钟事件属性;m,m1,m2表示多时钟序列,q,q1,q2表示多时钟属性;c,c1,c2表示不相同的时钟事件表达式。
一些序列和属性没有明确的前导时钟事件,根据时钟事件范围的流程,它们的初始时钟事件从外部时钟事件继承而来,在这个情况下,语义前导时钟会被认为是继承的。如下:
@(c) s |=> p and @(c1) p1
子属性p的语义前导时钟是继承的,因为p的初始时钟是流过|=>的时钟。
在所有的前导时钟相同时, 多时钟属性有唯一的语义前导时钟。
wire clk1, clk2;
logic a, b;
...
assign clk2 = clk1;
a1: assert property (@(clk1) a and @(clk2) b); // Illegal
a2: assert property (@(clk1) a and @(clk1) b); // OK
always @(posedge clk1) begin
a3: assert property(a and @(posedge clk2)); //Illegal
a4: assert property(a and @(posedge clk1)); // OK
end
断言a2和a4是合法的,而a3和a1是非法的,尽管a1 的时钟是相同的值,但他们不相同,因此a1有非唯一的语义前导时钟,断言a3和a4有@(posedge clk1)作为其推断时钟,与时钟@(posedge clk2)不同,因此a3有非唯一的语义前导时钟。