16.7 Sequences
- ##[*] 等价于 ##[0:$]
- ##[+] 等价于 ##[1:$]
- a ##N b //a为真,则过N拍b为真;
- (a ##1 b ##1 c) ##0 (d ##1 e ##1 f ) 等价于 a ##1 b ##1 c && d ##1 e ##1 f
- req ## [4:32] gnt //延迟可以是时间窗范围内任何值;
- req ## [4:$] gnt //使用$将时间窗扩展到无穷;
- a ##1 b ##1 c ##3 `true //`define true 1,序列可以通过连接`true来无条件扩展。
16.8 Declaring sequences
序列可以在module、interface、program、clocking block、package、compilation-unit scope、checker、generate block声明。
例如,仅当实际参数是细化时间常数时,对非类型化形式参数的引用可能出现在循环延迟范围、布尔值或序列的规范中。
//例1
sequence delay_example(x, y, min, max, delay1);
x ##delay1 y[*min:max];
endsequence
// Legal
a1: assert property (@(posedge clk) delay_example(x, y, 3, $, 2));
int z, d;
// Illegal: z and d are not elaboration-time constants
a2_illegal: assert property (@(posedge clk) delay_example(x, y, z, $, d));
下例,命名序列s1和s2在clk的连续posedge事件上进行计算,命名序列s3在clk的连续negedge事件上进行计算,命名序列s4在clk的连续交替posedge和negedge事件上进行计算:
//例2
sequence s1;
@(posedge clk) a ##1 b ##1 c;
endsequence
sequence s2;
@(posedge clk) d ##1 e ##1 f;
endsequence
sequence s3;
@(negedge clk) g ##1 h ##1 i;
endsequence
sequence s4;
@(edge clk) j ##1 k ##1 l;
endsequence
//例3
sequence s20_1(data,en);
(!frame && (data==data_bus)) ##1 (c_be[0:3] == en);
endsequence
命名序列s20_1没有指明时钟,在这种情况,时钟会从一些外部资源,如属性或断言语句继承,实例化一个命名序列如下所示:
//例4
sequence s;
a ##1 b ##1 c;
endsequence
sequence rule;
@(posedge sysclk)
trans ##1 start_trans ##1 s ##1 end_trans;
endsequence
上例等价于:
sequence rule;
@(posedge sysclk)
trans ##1 start_trans ##1 (a ##1 b ##1 c) ##1 end_trans ;
endsequence
以下示例说明了命名序列s1和s2之间的非法循环依赖关系:
//例5
sequence s1;
@(posedge sysclk) (x ##1 s2);
endsequence
sequence s2;
@(posedge sysclk) (y ##1 s1);
endsequence
16.8.1序列声明中的类型形式参数
序列的形式参数指定的数据类型可以是关键字untyped,如果形式参数的数据类型为非类型化,则该参数应为非类型化参数;将实际参数表达式绑定到具有非类型化数据类型的形式的语义应与非类型化形式的语义相同,如果非类型化的形式参数紧跟在形式参数列表中的数据类型之后,则应使用关键字untyped。
下面两个声明形式参数,s1所有的形式参数都是非类型,s 2的形式参数w和y是非类型,而形式参数x是bit型:
//例6
sequence s1(w, x, y);
w ##1 x ##[2:10] y;
endsequence
sequence s2(w, y, bit x);
w ##1 x ##[2:10] y;
endsequence
下面的s1和s2的实例是等价的:
s1(.w(a), .x(bit'(b)), .y(c))
s2(.w(a), .x(b), .y(c))
在s2的实例中,如果b是8bit宽,在上面的s2实例中,如果b恰好是8位宽,那么它将被逐位截断转换,因为它被传递给bit类型的形式参数。类似地,如果bit类型的表达式作为实际参数传递给byte类型的形式参数,则该表达式将扩展到byte。
如果在cycle_delay_range、boolean_abbrev, or a sequence_abbrev的规范中出现类型化形式参数的引用,则形式参数的类型应是shortint, int, or longint,
//例7
sequence delay_arg_example (max, shortint delay1, delay2, min);
x ##delay1 y[*min:max] ##delay2 z;
endsequence
parameter my_delay=2;
cover property (delay_arg_example($, my_delay, my_delay-1, 3));
上述cover属性等价于:
cover property (x ##2 y[*3:$] ##1 z);
下面显示了具有event类型形式参数的例子:
//例8
sequence event_arg_example (event ev);
@(ev) x ##1 y;
endsequence
cover property (event_arg_example(posedge clk));
等价于:
cover property (@(posedge clk) x ##1 y));
如果目的是将一个表达式作为实际参数传递,该表达式将与edge_identifier组合以创建event_expression,那么形式参数不应使用类型event键入:
//例9
sequence event_arg_example2 (reg sig);
@(posedge sig) x ##1 y;
endsequence
cover property (event_arg_example2(clk));
等价于:
cover property (@(posedge clk) x ##1 y));
另一个例子是使用局部变量对形式参数进行采样,展示了如何获得“按值传递”的效果当前不支持传递值作为参数传递模式:
//例10
sequence s(bit a, bit b);
bit loc_a;
(1'b1, loc_a = a) ##0
(t == loc_a) [*0:$] ##1 b;
endsequence
16.8.2序列声明中的局部变量形式参数
如果局部变量形式参数有方向input,则可以在端口项中的可选声明赋值中为该参数指定默认实际参数,为方向inout 或 output的局部变量参数,指定默认实际参数是非法的。
//例11
logic b_d, d_d;
sequence legal_loc_var_formal (
local inout logic a,
local logic b = b_d, // input inferred, default actual argument b_d
c, // local input logic inferred, no default actual argument
d = d_d, // local input logic inferred, default actual argument d_d
logic e, f // e and f are not local variable formal arguments
);
logic g = c, h = g || d;
...
endsequence
例11是使用局部变量形式参数、已命名序列的合法声明;
//例12
sequence illegal_loc_var_formal (
output logic a, // 非法:必须使用方向指定局部
local inout logic b,
c = 1'b0,// 为inoutde指定弄人实际参数是非法的
local d = expr,// 非法:类型必须明确指定
local event e, // 非法: 事件是16.6不允许的
local logic f = g // g 不应引用下面的局部变量,且必须从此声明向上解析
logic g = b;
...
endsequence
例12是使用局部变量形式参数、已命名序列的非法声明。
下例说明了局部变量形式参数的合法使用:
sequence sub_seq2(local inout int lv);
(a ##1 !a, lv += data_in)
##1 !b[*0:$] ##1 b && (data_out == lv);
endsequence
sequence seq2;
int v1;
(c, v1 = data)
##1 sub_seq2(v1) //lv通过为其分配v1值来初始化
//当实例sub_seq2(v1)匹配时, v1被指定为lv的值
##1 (do1 == v1);
endsequence
seq2的匹配行为等价于seq2_inlined:
sequence seq2_inlined;
int v1, lv;
(c, v1 = data) ##1
(
(1, lv = v1) ##0
(a ##1 !a, lv += data_in)
##1 (!b[*0:$] ##1 b && (data_out == lv), v1 = lv)
)
##1 (do1 == v1);
endsequence