Sequence定义

Sequence定义

  • 1. 基本操作符号
  • 2. and操作符号
  • 3. intersect操作符号
  • 4. or操作符号
  • 5. and / or应用
  • 6. first_match操作符号
  • 7. throughout操作符号
  • 8. within操作符号
  • 9. if操作符号
  • 10. 检测序列的终点
  • 11. 局部变量
  • 12. 调用方法
  • 13. 访问采样方法
  • 14. 系统函数和方法

1. 基本操作符号

  • ##用来表示周期延迟符号,例如##n表示在n个时钟周期后,##0表示在当前周期,即交叠周期;

    sequence a_b;
    	@(posedge clk) a ##1 b;
    endsequence
    
  • ##[min:max]表示在一个范围内的时钟周期延迟。min、max必须是非负数,序列会在从min到max时间窗口中最早的时间来匹配;

    sequence a_b;
    	@(posedge clk) a ##[1:5] b;
    endsequence
    
  • $用来表示无穷大的周期(在仿真结束前),但是一般不建议这么做,因为它会增大仿真评估序列的负担;

    sequence a_b;
    	@(posedge clk) a ##[1:$] b;
    endsequence
    
  • 事件也可以通过[*n]操作符号来表示重复。n须为非负数,其不能为$;

    sequence a_b;
    	@(posedge clk) a ##1 b[*2];  // a拉高一拍后,b要连续拉高两拍
    endsequence
    
  • 类似地,也可以用使用[*m:n]来表示一定范围内的重复事件;

    sequence a_b;
    	@(posedge clk) a ##1 b[*25];  // a拉高一拍后,b要连续拉高两拍到五拍
    endsequence
    
  • [=m]用来表示一个事件的连续性,需要重复发生m次,但是并不需要在连续周期内发生;

    sequence a_b;
    	@(posedge clk) a ##1 b[=3];  // b[=3]表示b必须在三个周期内为1,但是并不需要是连续的三个周期
    endsequence
    
  • 例如,执行了一次burst read操作,期望读的数据和ack信号在接下来的4个周期内返回,但又不需要连续的4个周期,即可以使用[=4]来表示;

  • 类似地,[=m:n]用来表示从最小m到最大n的重复发生的非连续周期次数;

  • a[*0]用来表示没有在任何正数时钟周期内有效;

  • 例如 a[*0:3] ##1 b ##1 c 与哪些情形匹配呢?(都匹配)

    • (b ##1 c)
    • (a ##1 b ##1 c)
    • (a ##1 a ##1 b ##1 c)
    • (a ##1 a ##1 a ##1 b ##1 c)

2. and操作符号

  • and用来表示两个序列需要保持匹配
  • 用法: SEQ1 and SEQ2
  • 下列情形将满足此操作符:
    • 在从同一起始点开始后,seq1和seq2均满足;
    • 满足的时刻发生在两个序列都满足的周期,即稍晚序列的满足时刻;
    • 两个序列的满足时间可以不同;
      Sequence定义_第1张图片
  • 如果操作符两边的序列都是用来衡量采样信号而非事件时序,那么则要求在相同周期内,and左右两边的序列都应该满足条件;
    Sequence定义_第2张图片

3. intersect操作符号

  • 和and操作符类型,只是需要两边的序列在同一时钟周期内匹配;
    Sequence定义_第3张图片
  • interact和and都要求同一时刻开始,但是interact多了一个条件,必须在同一时刻结束

4. or操作符号

  • or用来表示两个序列至少需要有一个满足
  • 用法: SEQ1 or SEQ2
  • 下列情形将满足次操作符
    • seq1和seq2都从同一个时刻被触发
    • 最终满足seq1或者满足seq2
    • 每一个序列的结束时间可以不同,结束时间以序列满足的最后一个序列时间为准
      Sequence定义_第4张图片
      Sequence定义_第5张图片

5. and / or应用

  • 如果burst write长度为1,那么写的长度可以为1、2或者4;
property BurstLengthValid
	@(posedge clk) disable iff(!rst)
	((burstLen == 4) |-> (wrlen ==1) or (wrlen == 2) or (wrlen == 4))
endproperty

assert property (BurstLengthValid);

6. first_match操作符号

  • first_match用来从多次满足的序列中选择第一次满足时刻,从而放弃其他满足时刻;

    sequence t1;
    	te1 ##[2:5] te2;
    endsequence
    
  • t1序列可以用来匹配te1 ##2 te2,te1 ##3 te2,te1 ##4 te2,或者te1 ##5 te2;

    sequence t1;
    	first_match(te1 ##[2:5] te2);
    endsequence
    
  • 此序列用来选择第一次匹配的时刻;

    sequence t2;
    	(1 ##[2:3] b) or (c ##[1:2] d);
    endsequence
    // a ##2 b
    // a ##3 b
    // c ##1 d
    // c ##2 d
    
    sequence ts2;
    	first_match(t2);
    endsequence
    
  • 对于上述的集中可能满足的sequence,ts2只会选择第一个满足上述sequence的时刻点;

  • 每一次PCI总线进入idle状态时,状态机也应该返回IDLE状态。由此,在时序信息上要求,如果frame和irdy信号保持至少两个周期以上为高时,系统的状态应该为idle状态;

    sequence checkBusIdle;
    	(##[2:$] (frame && irdy));
    endsequence
    
    property first_match_idle;
    	@(posedge clk) first_match(checkBusIdle) |-> (state == busidle);
    endproperty
    

7. throughout操作符号

  • 可以用来检查一个信号或者一个表达式在贯穿(throughout)一个序列时是否满足要求;
  • 用法: Sig1/Exp1 throughout Seq
  • 例如,在burst模式信号拉低以后的两个周期时,irdy/trdy也应该在连续七个周期内保持为低,同时burst模式信号也应该在这一连续周期内保持为低;
    sequence brust_rule1;
    	@(posedge mclk)
    	$fell(burst_mode) ##0 // 触发前置条件
    	(!burst_mode) throughtout (##2 ((trdy == 0) && (irdy == 0)) [*7]);
    endsequence
    

Sequence定义_第6张图片
Sequence定义_第7张图片

8. within操作符号

  • 可以用来检查一个序列与另外一个序列在部分周期长度上的重叠;
  • 用法:SEQ1 within SEQ2
  • 如果当seq1满足在seq2的一部分连续时钟周期内成立,seq1 within seq1成立;
  • 例如,trdy需要在irdy下拉的一个周期后保持7个周期为低,同时irdy也将保持8个周期为低,一下序列会在低11个周中周期满足
    Sequence定义_第8张图片

9. if操作符号

  • 可以在sequence中使用if…else;
  • 例如,当master_req为高时,下一个周期,req1或者req2应该为高,如果req1为高,则下一个周期ack1为高,如果req2为高,则下一个周期ack2为高;
    property master_child_reqs;
    	@(posedge clk) master_req ##1 (req1 || req2);
    	if(req1)
    		(##1 ack1);
    	else
    		(##1 ack2);
    endproperty
    
  • 在cache访问时,如果有cache lookup满足,那么状态机的状态应该为READ_CACHE,否则应该为REQ_OUT;
    property cache_hit_check;
    	@(posedge clk) (state == CACHE_LOOKUP) ##1 (CHit || CMiss) |->
    	if(CHit)
    		##1 (state == CACHE_READ);
    	else
    		##1 (state == REQ_OUT);
    endproperty
    
    assert property(cache_hit_check) else $error;
    

10. 检测序列的终点

  • 用法:SEQ.ended
  • 在某一时刻,序列如果及时抵达终点,那么条件满足;
  • 例如,在inst为高的下一个周期,序列e1应该结束或者已经结束;
    sequence e1;
    	@(posedge sysclk) $rose(ready) ##1 proc1 ##1 proc2;
    endsequence
    
    sequence rule;
    	@(posedge sysclk) reset ##1 inst ##1 e1.ended ##1 branch_back;
    endsequence
    
  • 在c拉起的下一个周期,a拉低b拉高的序列也应该结束;
    sequence aRbseq(aFell, bRose);
    	@(posedge clk) #fell(aFell) ##1;
    	$rose(bRose);
    endsequence
    
    property endCycle;
    	@(posedge clk) $rose(c) |=> aRbseq(a, b).ended;
    endproperty
    // 上面的逻辑也可以这样描述:
    // $rose(c) && $fell(a) |=> $rose(b);
    

Sequence定义_第9张图片

11. 局部变量

  • 局部变量可以在sequence或者property中使用;
  • 这些变量会伴随着sequence、property动态创建;
  • 每一个sequence实例都会有它自己的变量拷贝;
  • 例如,在cache rdDone拉高后,读出rdDone会在两个周期后,在其基础上加1,并作为wrData写入;
    sequence rd_cache_done;
    	##[1:5] rdDone;
    endsequence
    
    sequence check_reg_wr_data;
    	int local_data;
    	(rd_cache_done, local_data = cache_rd_data) ##2 (reg_wr_data == (local_data + 1));
    endsequence
    
  • 例如,如果read拉高,伴随readId,则下一次read必须在这一次read对应的readAck返回之后,才可以发起;
    sequence checkReadIdAck;
    	int loc_id;
    	($rose(read), loc_id == readId) |=>
    	not (($rose(read)&& readId == loc_id) [*1:$]) ##0 /* ##0即就是&& */
    	$rose(readAck) && readAckId == loc_id);
    endsequence
    
  • 需要先记录上一次read的readId,继而在接下来的周期,检查没有相同readId的read发起,直到对应readId的上一次read的readAck拉起,并且readAckId与之相同;

12. 调用方法

  • 在序列匹配时,可以调用task,void function和系统函数;
  • 例如,可以在s1序列末尾,分别打印出e和f变量被采样时的数值;
    sequence s1;
    	local v, w;
    	(a, v = 2) ##1
    	(b[->1], w = f, $display("b after a with = %h, w = %h\n", v, w));
    endsequence
    

13. 访问采样方法

  • 一些系统函数可以用来访问指定类型的变量采样:
    • 用来访问当前周期采样值
    • 用来访问上一个采样周期之
    • 用来检测采样变量的变化
  • $rose(expression[, clocking_event])$fell(expression[, clocking_event]) 用来表示与上一个采样周期相比,变量最低位是否跳变为1或者0,满足条件返回1,否则返回0;
  • clocking_event在sequence中不需要单独提供,因为sequence中一般会指定采样时钟;
  • 例如,在Req拉起的2个周期以后,Ack也应该拉高;
    Sequence定义_第10张图片
  • 例如,在write_en拉低后(表征发起写访问),write_data的数据内容不应该为X;
    property check_data_we;
    	@(posedge clk) $fell(write_en) |-> not ($isunknown(wr_data));
    endproperty
    
    

Sequence定义_第11张图片

  • $stable(expressin[, clocking_event]),用来表示在连续两个采样周期内,表达式的值保持不变,如果满足,返回1,否则,返回0;

  • 例如,在rd_en为高时,寄存器的值应该保持不变;

    property reg_rd_data_stable;
    	@(posedge clk) rd_en |-> $stable(reg_data);
    endproperty
    
  • $past(expr[, num_cycles][, gating_expr][,clocking_event])用来访问在过去若干采样周期前的数值;

  • 默认情况下。num_cycles = 1,即采样1个周期前的数值;

  • 例如,在ack拉高时的前两个周期,req信号应该为高;

    property ReqCauseAck;
    	@(posedge clk) $rose(ack) |-> $past(req, 2);
    endproperty
    
  • 例如,如果当前状态时CACHE_READ,那么上一个状态不应该是CACHE_MISS(如果cache丢失,那么无法从中读取数据)

property cache_read_chk;
	@(posedge clk) (state == CACHE_READ) |-> ($past(state) != CACHE_MISS);
endproperty
  • $rose / $fell / $stable也可以在过程块语句和连续赋值语句中使用,在类中class中的function中使用,编译报错,软件task中是没有办法指定时钟的;
    always @(posedge clk)
    	TestDone <= stimulus_over & $rose(unit_done);
    
    always @(posedge clk) begin
    	if($stable(my_sig)) begin
    		$display($time, "my_sig is stable from previous clk");
    	end
    end
    
    assign intr_cleared = $fell(intr, @(posedge clk));
    assign intr_set = $rose(intr, @(posedge clk));
    

14. 系统函数和方法

  • 类似于之前的访问采样方法,还可以使用其他一些系统函数和方法,在sequence / property / assertion中使用:

    • $countbits
    • $onehot
    • $isunknown
    • $countones
  • 这些系统函数(不依赖时钟)也可以用在一般过程语句块和赋值语句中

  • $countbits(expression, control_bit)用来计算expression中匹配control_bit数值的位数;

  • $countones(expression)$countbits(expression, ‘1)—致,即计算expression中为1的位数

  • $onehot(expression)$countbits(expression, ‘1)==1—致,即检查expression中是否有且只有1位为1

  • $isunknown(expression)$countbits(expression, ‘x, ‘z)!=0一致,即检查expression中是否有x或者z。

  • 在assertion或者property中,可以通过”disable iff“来给assertion做局部的条件控制;

  • 在全局控制方面,我们也可以通过系统函数对property模块或者实例做出控制:

    • $asserton,默认控制,用来打开所有的assertion
    • $assertoff,暂时停止assertion运行
    • $assertkill,终止所有执行的assertion
    $assertoff (level,[list of module, instance or assertion_identifier]);
    $assertkill (level,[list of module, instance or assertion_identifier]);
    $asserton (level,[list of module,instance or assertion_identifier] );
    
  • level=0,表示当前模块或者层次下的所有assertion;

  • level=n,表示当前模块或者层次下n层范围中de assertion;

  • assertion_identifier表示property的名字或者assertion的label;

  • 例如,在reset阶段停止所有的assertion,并且在其复位之后,使能所有的assertion

    module assert_control();
    initial begin: disable_assert_during_reset
    	@(negedge top_tb.reset_n)  // 复位时暂停
    		$display("Disabling assertion during reset");
    		$assertoff(0, top_tb.cpu_inst1);
    	@(posedge top_tb.reset_n)  // 复位后开启
    		$display("enabling assertions after reset" );
    		$asserton(0, top_tb.cpu_inst1);
    end
    endmodule
    

你可能感兴趣的:(UVM,systemverilog,IC验证,UVM)