SVA 断言 note

断言概念

一般,断言是基于时序逻辑的,单纯进行组合逻辑的断言很少见,因为太费内存(时序逻辑是每个时钟周期判断一次,而组合逻辑却是每个时钟周期内判断多次,内存吃不消)。
因此,写断言的一般规则是: time + event,要断定发生什么event,首先要指定发生event的时间,例如:

  • 每个时钟上升沿 + 发生某事;
  • 某信号下降时 + 发生某事;

sequence / property

  • 序列块:
sequence name;
    ....; 
endsequence
  • 属性块:
property name;
    ...;
endproperty

从定义来讲,sequence块用于定义一个事件(砖),而property块用于将事件组织起来,形成更复杂的一个过程(楼)。sequence块的内容不能为空,你写乱字符都行,但不能什么都没有。sequence也可以包含另一个sequence, 如:

 sequence s1;

   s2(a,b);

endsequence  //s1和s2都是sequence块

sequence块和property块都有name,使用assert调用时都是:assert property(name);
在SVA中,

  • sequence块一般用来定义组合逻辑断言,
  • property一般用来定义一个有时间观念的断言,它会常常调用sequence,
  • 一些时序操作如“|->”只能用于property就是这个原因。

注:以下介绍的SVA语法,既可以写在sequence中,也可以写在property中,语法是通用的。

Table 1: SVA system functions
Table 1: SVA system functions
在这里插入图片描述
Table 2: SVA operators

在这里插入图片描述
Table 3: Repetition operators

NOTE: The table above lists operators most frequently used in SVAs. There are several more - intersect, throughout, within, etc. In my opinion, while these operators are powerful, they lead to confusion. Most assertions can be written using the above table.

断言的时间点
断言要熟记两个时间点:采样时刻和匹配时刻,断言在preponed域采样,在observed域执行检查(关于时钟域也有很多介绍,之后我再写一个简单明了的吧)。简单来说断言的采样点处于时钟上升沿之前、module中@clk采样时刻之后,也就是说采样到的是上升沿之前的”旧值”。验证环境中,@clk进行采样时的采样顺序可以简记为module @clk采样(旧值)->断言采样(旧值)->program @clk采样(新值,跳变后的)。

在这里插入图片描述

数字前端的功能验证利器——SVA断言学习笔记

and运算符
and运算符用来连接两个事件(多为序列),当两个事件均成功时匹配成功,需要注意的是两个事件必须有相同的起始点,但是可以有不同的结束点。举个简单的例子,(a ##[2:4] b) and (a ##5 c)在波形中可见,100ns处(a ##[2:4] b)匹配成功,140ns处整个序列匹配成功,其他时间都是匹配失败的(假“失败”)。
在这里插入图片描述
说一下and和&在断言中的区别与联系。a & b也是要a和b同时成立在是成功,不过此式中a和b必须为表达式,匹配也只能在每一拍内进行;而a and b中的a、b既可以是表达式又可以是序列,是可以进行跨拍匹配的。例如(sig_a == 5) & (sig_b == 3)也可以写成(sig_a == 5) and (sig_b == 3),但是(a ##[2:4] b) and (a ##5 c)不可以写作(a ##[2:4] b) & (a ##5 c)。

or运算符
and运算符用来连接两个事件(多为序列),当两个事件任一匹配成功则整体成功,与|的区别和之前类似,or可以连接两个表达式或是两个序列,|只能连接两个表达式。

intersect运算符
我认为intersect运算符是最重要的一个运算符,后面会大量的用到。intersect和and有一些类似,都是连接两个事件,两个事件均成功整个匹配才成功。不过intersect多了一个条件,那就是两个事件必须在同一时刻结束(and已经需要保证两个事件同一时刻开始了),换句话说a intersect b能匹配成功,a、b两个序列的长度必须相等。

通过几个例子来深入理解下,(a ##[1:2] b) intersect (c ##[2:3] d),见波形如下图。图中黄色点为a ##[1:2] b匹配成功时刻点,蓝色为c ##[2:3] d匹配成功点,根据我们之前的分析,intersect连接的两个序列必须有同样的结束时刻,因此整个序列匹配的时间点一定在黄色和蓝色重合的点中,那么我们需要分析下起始点。对于180ns,a ##[1:2] b起始点为160ns或140ns,c ##[2:3] d的起始成功点为140ns或120ns(如果觉得这样比较乱,那就顺着从开头找),因此起点在140ns终点在180ns的波形符合序列(a ##[1:2] b) intersect (c ##[2:3] d),匹配成功;同理起点在160ns终点在200ns的波形符合序列,起点在180ns终点在220ns的波形也符合序列。
在这里插入图片描述

记住intersect最重要的特点:连接打两个序列有相同的起点相同的起点相同的终点和必然相同的序列长度,这一点之后会非常好用。

within运算符
a within b含义是在事件b(序列b)匹配期间,事件a(序列a)至少出现1次则匹配成功,否则失败。再正规一些的表述就是序列a在序列b开始到结束的范围内发生,序列b开始匹配点必去在序列a开始 匹配点之前发生,序列a的结束匹配点必须在序列b结束匹配点之前结束。不过在此我自己有一个疑点,序列b应当包含序列a,那么序列b和序列a的起始时间或结束时间相同是否可以,对于这点暂做遗留问题,我亲自仿真下寻找答案(暂时认为是不可以的)。

还是举一个简单的栗子看看波形吧,(a ##1 b[=3]) within (c ##1 d[->1])。
在这里插入图片描述

40ns~200ns是一次成功的匹配,(c ##1 d[->1])在40ns开始在200ns成功,(a ##1 b[=3])在80ns开始在160ns(和180ns、200ns…)匹配成功,(a ##1 b[=3])完美包裹在(c ##1 d[->1])之中;240ns~320ns是一次典型的匹配失败,请自行分析下。

因为后面用到within很少,我就不再深入探究了。

throughout运算符
throughout运算符和intersect有些接近(我个人认为throughout是可以完全被intersect取代的,所有throughout都可以写成intersect),不过区别在于throughout必须连接一个表达式和一个序列即req throughout seq,含义是在seq匹配起始到结束期间,req都必须成立。例如a throughout (b ##1 c[->1])就要求从b有效开始,直到c第一次有效结束,这段期间a必须始终保持有效,如下波形图60ns~140ns就是一次典型的匹配成功。
在这里插入图片描述

这个我用的的确不多,就写这么多吧。

first_match
含义是只使用第一次匹配,丢弃其他时刻点的匹配。

在之前所写的事件描述中我们提到过,仿真器会在每个时钟窗口去匹配,大概率会匹配成功多次。在一些情景下,我们只关心第一次出现的状况,例如我们认定某一些信号组合是不能出现的,一旦出现了就应该报error提醒我们进行检查,这种情况下我们只需要关注第一次出现的时间点就可以了,那么我们就可以使用first_match了。不过说实话这个运算符在断言中用的不多。


语法1:信号(或事件)间的“组合逻辑”关系:

  • 常见的有:&&, ||, !, ^
  • a和b哪个成立都行,但如果都成立,就认为是a成立:firstmatch(a||b),与“||”基本相同,不同点是当a和b都成立时,认为a成立。
  • a ? b:c ———— a事件成功后,触发b,a不成功则触发c

语法2:在“时序逻辑”中判断独立的一根信号的行为:

    @ (posedge clk) A事件;  // ———— 当clk上升沿时,如果发生A事件,断言将报警。

边沿触发内置函数:(假设存在一个信号a)
$rose( a );———— 信号上升
$fell( a );———— 信号下降
$stable( a );———— 信号值不变

  • @ (posedge clk) a |=> b ———— 断定clk上升沿后,a事件开始发生,下一个时钟沿后,b事件开始发生。

  • @ (posedge clk) a |=>##2b ———— 断定clk上升沿后,a事件开始发生,下三个时钟沿后,b事件开始发生。

  • overlapped implication采用"|->"操作符,只有先行词判断为真后,后继才会在同一个时钟沿被检测.例子:

property p;
  @(posedge clk) a |-> b;//在上升沿到来时,若a=1,则在同一个时钟周期继续检查b是否为1,若为1,则判断为真
endproperty
a: assert property(p);
  • Non-overlapped implication采用"|=>"操作符,只有先行词判断为真后,后继才会在下一个时钟沿被检测.例子:
property p;
  @(posedge clk) a |=> b;//当时钟沿到来时检测a是否为1,若为1,则在下一个时钟沿继续检测b
endproperty
a: assert property(p);
sequence seq_rose;
  @(posedge clk) $rose(a);//如果在时钟有效沿a跳变为1,则断言成功
endsequence

语法5:总线的断言函数

总线就是好多根bit线,共同表示一个数。SVA提供了多bit状态一起判断的函数,即总线断言函数:

  • $onehot(BUS) ————BUS中有且仅有1 bit是高,其他是低。
  • $onehot0(BUS) ————BUS中有不超过1 bit是高,也允许全0。
  • $isunknown(BUS) ————BUS中存在高阻态或未知态。
  • countones(BUS)==n ————BUS中有且仅有n bits是高,其他是低。

语法6:屏蔽不定态

当信号被断言时,如果信号是未复位的不定态,不管怎么断言,都会报告:“断言失败”,为了在不定态不报告问题,在断言时可以屏蔽。如:

@(posedge clk) (q == $past(d))  //,当未复位时报错,屏蔽方法是将该句改写为:
@(posedge clk) disable iff (!rst_n) (q == $past(d))  //rst是低电平有效

Forbidding a property 禁止一个property

sequence seq;
  @(posedge clk) a ##2 b;
endsequence
 
property p;
  not seq;//not表示对sequence取反,即sequence成功时,property失败
endproperty
a_1: assert property(p);

断言编译modelsim

在modelsim中开启断言编译和显示功能:

  • 【编译verilog代码时按照system verilog进行编译】 vlog -sv abc.v
  • 【仿真命令加一个-assertdebug】 vsim -assertdebug -novopt testbench
  • 【如果想看断言成功与否的分析,使用打开断言窗口的命令】 view assertions

带时序关系的sequence

在SVA中时钟延时用符号"##"来表示,如“##2”表示延时两个时钟周期。看例子:

sequence seq;
  @(posedge clk) a ##2 b; //在时钟上升沿到来是检查a是否为1,若不为1则断言失败
                          //若a为1,则检查两个周期之后b是否为1,若不为1,断言失败
endsequence

Repetition Operators 重复操作

signal [*n] 
 
或
 
sequence [*n]

property p;
  @(posedge clk) a |-> ##1 b ##1 b ##1 b;//在当前时钟沿若a=1,则在接下来的3个时钟b=1
endproperty
a: assert property(p);
//所以上面的语句可以重写为:
property p;
  @(posedge clk) a |-> ##1 b[*3];
endproperty
a: assert property(p);
[*n : $], [*] [+]连续循环,是针对sequence的连续循环
[* n:$]结构类似于[* n:m],除了m被$符取代,$符代表无限的意思,并且n意味着重复最少n个周期。
[*]是[* 0:$]的缩写,表示重复至少0次,最多无限次。 
[+]是[* 1:$]的缩写,表示重复至少1次,最多无限次。

在这里插入图片描述

property p;
  @(posedge clk) a |-> ##1 b ##1 b ##1 b;
endproperty
a: assert property(p);
//The above property checks that, if the signal “a” is high on given posedge of the clock, the signal “b” should be high for 3 consecutive clock cycles.
//the same  with repetition operator above sequence can be re-written as,
property p;
  @(posedge clk) a |-> ##1 b[*3];
endproperty
a: assert property(p);

go to repetition

The go-to repetition operator is used to specify that a signal will match the number of times specified not necessarily on continuous clock cycles.

signal [->n]
//重复n次,且不必是连续时钟周期

property p;
  @(posedge clk) a |-> ##1 b[->3] ##1 c;
endproperty
a: assert property(p);

//The above property checks that, if the signal “a” is high on given posedge of the clock, the signal “b” should be high for 3 clock cycles followed by “c” should be high after ”b” is high for the third time.

SystemVerilog Assertions (SVA)

Nonconsecutive repetition

This is very similar to “go to” repetition except that it does not require that the last match on the signal repetition happens in the clock cycle before the end of the entire sequence matching.

signal [=n]

Only expressions are allowed to repeat in “go to” and “nonconsecutive” repetitions. Sequences are not allowed.

它与上面go-to类似,唯一的区别就是它不要求信号重复的最后一次匹配发生在整个序列匹配结束之前的时钟周期中,格式如下:

signal [=n]
[=n][->n]的区别: 
a ##1 b[->1:3] ##1 c  // E.g. a !b b b !b !b b c
//也就是说最后一次必须匹配
a ##1 b [=1:3] ##1 c // E.g. a !b b b !b !b b !b !b c
//在跳变到c之前的最后一次不一定要匹配

SV之Assertions 断言


/*--------------------------------------
// AXI virtual interface
// description : axi virtual interface which is a connection pool interface for DUT and Virtual test
// file : axi_vif.sv
// author : SeanChen
// date : 2013/04/10
---------------------------------------*/

`timescale 1ns/10ps

interface AXI_vif #(
				parameter integer C_AXI_ID_WIDTH 	= 10, // default 4
				parameter integer C_AXI_ADDR_WIDTH 	= 32,
                parameter integer C_AXI_REG_WITH    = 4,
				parameter integer C_AXI_DATA_WIDTH 	= 32,
				parameter integer C_AXI_LEN_WIDTH 	= 8,  // default 4
				parameter integer C_AXI_SIZE_WIDTH 	= 3,
				parameter integer C_AXI_BURST_WIDTH = 2,
				parameter integer C_AXI_CACHE_WIDTH = 4,
				parameter integer C_AXI_PROT_WIDTH 	= 3,
				parameter integer C_AXI_QOS_WIDTH	  = 4,
				parameter integer C_AXI_STRB_WIDTH 	= 4,
				parameter integer C_AXI_RESP_WIDTH 	= 2,
        parameter integer C_AXI_LOCK_WIDTH  = 1,
        parameter integer C_AXI_VALID_WIDTH = 1,
        parameter integer C_AXI_READY_WIDTH = 1,
        parameter integer C_AXI_LAST_WIDTH  = 1,
        parameter string name = "vif"

)( input AXI_ACLK, input AXI_ARESET_N);

	// control flags
	  bit has_checks 		= 1;
	  bit has_coverage	= 1;

	// AXI global signals
	//  logic [0:0]	AXI_ARESET_N;
  //  logic [0:0]	AXI_ACLK;

	// AXI address write phase
    logic [C_AXI_ID_WIDTH-1:0]		AXI_AWID; //axi4 remove it
    logic [C_AXI_ADDR_WIDTH-1:0]	AXI_AWADDR;
    logic [C_AXI_REG_WITH-1:0]    AXI_AWREG;
    logic [C_AXI_LEN_WIDTH-1:0]		AXI_AWLEN;
    logic [C_AXI_SIZE_WIDTH-1:0]	AXI_AWSIZE;
    logic [C_AXI_BURST_WIDTH-1:0]	AXI_AWBURST;
    logic [C_AXI_LOCK_WIDTH-1:0]	AXI_AWLOCK;
    logic [C_AXI_CACHE_WIDTH-1:0]	AXI_AWCACHE;
    logic [C_AXI_PROT_WIDTH-1:0]	AXI_AWPROT;
    logic [C_AXI_QOS_WIDTH-1:0]		AXI_AWQOS;
    logic [C_AXI_VALID_WIDTH-1:0]	AXI_AWVALID;
    logic [C_AXI_READY_WIDTH-1:0]	AXI_AWREADY;

	// AXI data write phase
    logic [C_AXI_ID_WIDTH-1:-0]   AXI_WID;
    logic [C_AXI_DATA_WIDTH-1:0]	AXI_WDATA;
    logic [C_AXI_STRB_WIDTH-1:0]	AXI_WSTRB;
    logic [C_AXI_LAST_WIDTH-1:0]	AXI_WLAST;
    logic [C_AXI_VALID_WIDTH-1:0] AXI_WVALID;
    logic [C_AXI_READY_WIDTH-1:0]	AXI_WREADY;

	// AXI response write phase
    logic [C_AXI_ID_WIDTH-1:0]		AXI_BID;
    logic [C_AXI_RESP_WIDTH-1:0]	AXI_BRESP;
    logic [C_AXI_VALID_WIDTH-1:0]	AXI_BVALID;
    logic [C_AXI_READY_WIDTH-1:0]	AXI_BREADY;

	// AXI address read phase
    logic [C_AXI_ID_WIDTH-1:0]		AXI_ARID;
    logic [C_AXI_ADDR_WIDTH-1:0]	AXI_ARADDR;
    logic [C_AXI_REG_WITH-1:0]    AXI_ARREG;
    logic [C_AXI_LEN_WIDTH-1:0]		AXI_ARLEN;
    logic [C_AXI_SIZE_WIDTH-1:0]	AXI_ARSIZE;
    logic [C_AXI_BURST_WIDTH-1:0]	AXI_ARBURST;
    logic [C_AXI_LOCK_WIDTH-1:0]	AXI_ARLOCK;
    logic [C_AXI_CACHE_WIDTH-1:0]	AXI_ARCACHE;
    logic [C_AXI_PROT_WIDTH-1:0]	AXI_ARPROT;
    logic [C_AXI_QOS_WIDTH-1:0]		AXI_ARQOS;
    logic [C_AXI_VALID_WIDTH-1:0]	AXI_ARVALID;
    logic [C_AXI_READY_WIDTH-1:0]	AXI_ARREADY;

	// AXI data read phase
    logic [C_AXI_ID_WIDTH-1:0]		AXI_RID;
    logic [C_AXI_DATA_WIDTH-1:0]	AXI_RDATA;
    logic [C_AXI_RESP_WIDTH-1:0]	AXI_RRESP;
    logic [C_AXI_LAST_WIDTH-1:0]	AXI_RLAST;
    logic [C_AXI_VALID_WIDTH-1:0]	AXI_RVALID;
    logic [C_AXI_READY_WIDTH-1:0]	AXI_RREADY;

    // write data count
    // read data count

	/*-------------------------------------------
	// modport for each module type, like master, slave...
	// please add your modports here
	---------------------------------------------*/

	// modports in slave interfaces
	modport Slave ();

	// modports in master interfaces
	modport Master ();

	// modports in monitor interface
	modport Monitor ();

	/*-----------------------------------------------
	// Assertions -> axi_assertioms.sv
	// please add your assertion rules here
	------------------------------------------------*/

always @(negedge AXI_ACLK)
begin

// write address must not be X or Z during address write phase
assertWriteAddrUnknown:assert property (
    disable iff(!has_checks)
		  ($onehot(AXI_AWVALID) && $onehot(AXI_AWREADY) |-> !$isunknown(AXI_AWADDR)))
		else
		  $error({$psprintf("ERR_AXI_AWADDR %s went to X or Z during address write phase when AXI_AWVALID=1", name)});

// write data must not be X or Z during data write phase
assertWriteDataUnknown:assert property (
    disable iff(!has_checks)
		  ($onehot(AXI_WVALID) && $onehot(AXI_WREADY) |-> !$isunknown(AXI_WDATA)))
		else
		  $error({$psprintf("ERR_AXI_WDATA %s went to X or Z during data write phase when AXI_WVALID=1", name)});

// write resp must not be X or Z during resp write phase
assertWriteRespUnKnown:assert property (
    disable iff(!has_checks)
      ($onehot(AXI_BVALID) && $onehot(AXI_BREADY) |-> !$isunknown(AXI_BRESP)))
    else
      $error({$psprintf("ERR_AXI_BRESP %s went to X or Z during response write phase when AXI_BVALID=1", name)});

// read address must not be X or Z during address read phase
assertReadAddrUnKnown:assert property (
    disable iff(!has_checks)
      ($onehot(AXI_ARVALID) && $onehot(AXI_ARREADY) |-> !$isunknown(AXI_ARADDR)))
    else
      $error({$psprintf("ERR_AXI_ARADDR %s went to X or Z during address read phase when AXI_ARVALID=1", name)});

// read data must not be X or Z during read data phase
assertReadDataUnKnown:assert property (
    disable iff(!has_checks)
      ($onehot(AXI_RVALID) && $onehot(AXI_RREADY) |-> !$isunknown(AXI_RDATA)))
    else
      $error({$psprintf("ERR_AXI_AWDATA %s went to X or Z during data read phase when AXI_RVALID=1", name)});

// assert each pin has value not unknown

end

endinterface : AXI_vif

//----------------------------------------------------------------------
//   Copyright 2012 Mentor Graphics Corporation
//   All Rights Reserved Worldwide
//
//   Licensed under the Apache License, Version 2.0 (the
//   "License"); you may not use this file except in
//   compliance with the License.  You may obtain a copy of
//   the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in
//   writing, software distributed under the License is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied.  See
//   the License for the specific language governing
//   permissions and limitations under the License.
//----------------------------------------------------------------------
//
// APB Protocol Monitor
//
interface apb_monitor #(int no_slaves = 16, int addr_width = 32, int data_width = 32)
  (
  input PCLK,
  input PRESETn,
  input[addr_width-1:0] PADDR,
  input[data_width-1:0] PWDATA,
  input[data_width-1:0] PRDATA,
  input[no_slaves-1:0] PSEL,
  input PWRITE,
  input PENABLE,
  input PREADY,
  input PSLVERR);

// Check for unknown signal values:

// Reuseable property to check that a signal is in a safe state
property SIGNAL_VALID(signal);
  @(posedge PCLK)
  !$isunknown(signal);
endproperty: SIGNAL_VALID

RESET_VALID: assert property(SIGNAL_VALID(PRESETn));
PSEL_VALID: assert property(SIGNAL_VALID(PSEL));

// Reuseable property to check that if a PSEL is active, then
// the signal is valid
property CONTROL_SIGNAL_VALID(signal);
  @(posedge PCLK)
  $onehot(PSEL) |-> !$isunknown(signal);
endproperty: CONTROL_SIGNAL_VALID

PADDR_VALID: assert property(CONTROL_SIGNAL_VALID(PADDR));
PWRITE_VALID: assert property(CONTROL_SIGNAL_VALID(PWRITE));
PENABLE_VALID: assert property(CONTROL_SIGNAL_VALID(PENABLE));

// Check that write data is valid if a write
property PWDATA_SIGNAL_VALID;
  @(posedge PCLK)
  ($onehot(PSEL) && PWRITE) |-> !$isunknown(PWDATA);
endproperty: PWDATA_SIGNAL_VALID

PWDATA_VALID: assert property(PWDATA_SIGNAL_VALID);

// Check that if PENABLE is active, then the signal is valid
property PENABLE_SIGNAL_VALID(signal);
  @(posedge PCLK)
  $rose(PENABLE) |-> !$isunknown(signal)[*1:$] ##1 $fell(PENABLE);
endproperty: PENABLE_SIGNAL_VALID

PREADY_VALID: assert property(PENABLE_SIGNAL_VALID(PREADY));
PSLVERR_VALID: assert property(PENABLE_SIGNAL_VALID(PSLVERR));

// Check that read data is valid if a read
property PRDATA_SIGNAL_VALID;
  @(posedge PCLK)
  ($rose(PENABLE && !PWRITE && PREADY)) |-> !$isunknown(PRDATA)[*1:$] ##1 $fell(PENABLE);
endproperty: PRDATA_SIGNAL_VALID

//PRDATA_VALID: assert property(PRDATA_SIGNAL_VALID);

// Check that only one PSEL line is valid at a time:
property PSEL_ONEHOT0;
  @(posedge PCLK)
  $onehot0(PSEL);
endproperty: PSEL_ONEHOT0

PSEL_ONLY_ONE: assert property(PSEL_ONEHOT0);

// PENABLE goes low once PREADY is sampled
property PENABLE_DEASSERTED;
  @(posedge PCLK)
  $rose(PENABLE && PREADY) |=> !PENABLE;
endproperty: PENABLE_DEASSERTED

PENABLE_DEASSERT: assert property(PENABLE_DEASSERTED);

// From PSEL active to PENABLE active is 1 cycle
property PSEL_TO_PENABLE_ACTIVE;
  @(posedge PCLK)
  (!$stable(PSEL) && $onehot(PSEL)) |=> PENABLE;
endproperty: PSEL_TO_PENABLE_ACTIVE

PSEL_2_PENABLE: assert property(PSEL_TO_PENABLE_ACTIVE);

// FROM PSEL being active, then signal must be stable until end of cycle
property PSEL_ASSERT_SIGNAL_STABLE(signal);
  @(posedge PCLK)
  (!$stable(PSEL) && $onehot(PSEL)) |=> $stable(signal)[*1:$] ##1 $fell(PENABLE);
endproperty: PSEL_ASSERT_SIGNAL_STABLE

PSEL_STABLE: assert property(PSEL_ASSERT_SIGNAL_STABLE(PSEL));
PWRITE_STABLE: assert property(PSEL_ASSERT_SIGNAL_STABLE(PWRITE));
PADDR_STABLE: assert property(PSEL_ASSERT_SIGNAL_STABLE(PADDR));
PWDATA_STABLE: assert property(PSEL_ASSERT_SIGNAL_STABLE(PWDATA & PWRITE));

// Functional Coverage for the APB transfers:
//
// Have we seen all possible PSELS activated?
// Have we seen reads/writes to all slaves?
// Have we seen good and bad PSLVERR results from all slaves?
covergroup APB_accesses_cg();

option.per_instance = 1;

RW: coverpoint PWRITE {
  bins read = {0};
  bins write = {1};
}
ERR: coverpoint PSLVERR {
  bins err = {1};
  bins ok = {0};
}

APB_CVR: cross RW, ERR;

endgroup: APB_accesses_cg

// Array of these covergroups
APB_accesses_cg APB_protocol_cg[no_slaves];

// Creation the covergroups
initial begin
  foreach(APB_protocol_cg[i]) begin
    APB_protocol_cg[i] = new();
  end
end

// Sampling of the covergroups
sequence END_OF_APB_TRANSFER;
  @(posedge PCLK)
  $rose(PENABLE & PREADY);
endsequence: END_OF_APB_TRANSFER

cover property(END_OF_APB_TRANSFER) begin
  foreach(APB_protocol_cg[i]) begin
    if(PSEL[i] == 1) begin
      APB_protocol_cg[i].sample();
    end
  end
end

endinterface: apb_monitor
//uart tx
property busy_bit;
  @(posedge PCLK)
  tx_state == IDLE ##1 tx_state == START |->
    ((busy == 1) && (tx_state != IDLE))[*1:$] ##1 (tx_state == START);
endproperty: busy_bit

TX_BUSY_CHK: assert property(busy_bit);

//uart rx
property rx_parity;
  @(posedge PCLK)
  $rose(rx_state == STOP1) |=> parity_error == rx_buffer[9];
endproperty: rx_parity

RX_PE_CHK: assert property(rx_parity);

property rx_framing;
  @(posedge PCLK)
  $rose((rx_state == STOP1) && (enable == 1) && (bit_counter == 4'hf)) |=>
    rx_buffer[8] == ~filtered_rxd;
endproperty: rx_framing

RX_FE_CHK: assert property(rx_framing);

property rx_break;
  @(posedge PCLK)
  $rose((rx_state == STOP2) && ~(|{filtered_rxd, rx_buffer})) |=> break_error;
endproperty: rx_break

RX_BE_CHK: assert property(rx_break);

property rx_overrun_prop;
  @(posedge PCLK)
  $rose((rx_state == STOP2) && (rx_fifo_count == 4'hf)) |=> (rx_overrun == 1);
endproperty: rx_overrun_prop

RX_OE_CHK: assert property(rx_overrun_prop);


//uart_tx_fifo
property fifo_full_prop;
  @(posedge clk)
  fifo_full |-> (count == 5'b10000);
endproperty: fifo_full_prop

property fifo_empty_prop;
  @(posedge clk)
  fifo_empty |-> (count == 0);
endproperty: fifo_empty_prop

property fifo_niether;
  @(posedge clk)
  (!fifo_full && !fifo_empty) |-> ((count > 0) && (count < 5'b10000));
endproperty: fifo_niether

TX_FIFO_FULL_CHK: assert property(fifo_full_prop);
TX_FIFO_EMPTY_CHK: assert property(fifo_empty_prop);
TX_FIFO_OK_CHK: assert property(fifo_niether);
/* File name : bus_arb_assertions.svh */
prop_a_cnt: assert property (
    @(posedge clk) disable iff (rst)
    a_vld |-> (a_cnt == $past(a_cnt) + 1));

property valid_state;
    @(posedge clk) disable iff (rst)
    $onehot0(current_state);
endproperty
prop_valid_state: assert property (valid_state);

// ... other assertions and cover props
// FIFO level cannot go down without a pop.
property FifoLevelCheck;
   @(posedge clk) disable iff (rst)
   (!rd_vld) |->
   ##1 (fifo_level >= $past(fifo_level));
endproperty
FifoLevelCheck_C: assume property (FifoLevelCheck);

// when there's a no_space_err, the no_space_ctr_incr signal is flagged
// for exactly once clock
property NoSpaceErrCtr;
   @(posedge clk) disable iff (rst)
   (no_space_err) |-> (no_space_ctr_incr ^ $past(no_space_ctr_incr));
endproperty
NoSpaceErrCtr_A: assert property (NoSpaceErrCtr);

// if there's an uncorrectable err during an ADD request,
// err_cnt should be incremented in the same cycle and an interrupt
// should be flagged in the next cycle
property AddUncorErrCheck;
   @(posedge clk) disable iff (rst)
   (uncor_err && (req_type == ADD)) |->
   (err_cnt_incr ##1 intr);
endproperty
AddUncorErrCheck_A: assert property (AddUncorErrCheck);

// INIT and FLUSH transactions should complete within MAX_LATENCY.
property LatencyCheck;
   @(posedge clk) disable iff (rst)
   ((req_type == INIT) ||
    (req_type == FLUSH)) |->
   (block_latency < MAX_LATENCY);
endproperty
LatencyCheck_A: assert property(LatencyCheck);

// interrupt should never get set
property InterruptCheck;
   @(posedge clk) disable iff (rst)
   (!intr);
endproperty
InterruptCheck_A: assert property (InterruptCheck);

// wr_data should be stable until wr_ack arrives
property WriteData;
   @(posedge clk) disable iff (rst)
   (wr && !wr_ack) |->
   ##1 (wr_data == $past(wr_data));
endproperty
WriteData_A: assert property (WriteData);

// wr_ack should be asserted only when there's a wr request
property WriteAck;
   @(posedge clk) disable iff (rst)
   (!wr) |-> (!wr_ack);
endproperty
WriteAck1_C: assume property (WriteAck1);

// if wr is asserted, it should remain high until wr_ack is received
property WriteAck2;
   @(posedge clk) disable iff (rst)
   (wr && (!wr_ack)) |-> ##1 wr;
endproperty
WriteAck2_A: assert property (WriteAck2);

// output is not x or z when valid is high
DoutCheck: assert property (@(posedge clk) valid |-> (!$isunknown(dout)));

// Check if ack arrives 3 to 5 clocks after a request
assert property (@(posedge clk) req |-> ##[3:5] ack);

// check if interrupt propagates when intr is enabled
generate
    for (i=0; i < 16; i++) begin: INTR0
        Intr0 : assert property (@(posedge clk) disable iff (rst) 
            ((intr_enable[i] & intr_status[i] ) |-> ##1 intr))
        else `uvm_error ("INTR_ERR", $sformatf ( "[%m] : Interrupt not propagating"))
    end
endgenerate

// When vld rises high -
// .. a is repeated twice then 
// .. after 2 clocks b is repeated 3 to 4 times with gaps in between, 
// .. after last occurence of b, exactly 1 clock later c occurs
// .. one clock after c, d occurs 3 times non-consecutively,
// .. after last occurence of d, there are a variable number of empty
// .. clocks, then e happens
property Repeat1;
    @(posedge clk) disable iff (rst)
    $rose(vld) |-> (a[*2] ##2 b[->3:4] ##1 c ##1 d[=3] ##1 e);
endproperty
Repeat1_A: assert property (Repeat1);

// Going crazy with repetition operators
property Repeat2;
    @(posedge clk) disable iff (rst)
    $fell(reset) |-> ##[3:5] ((st1 ##6 st2) [*2]) ##2 (ready [*1:5]);
endproperty
Repeat2_A: assert property (Repeat2);
  • 4
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值