第五章 采样值函数$rose,$fell


                                                     图5.1采样值函数$rose,$fell-基础

 这些采样值函数允许先行和/或随后被边缘触发。 $rose表示在前一个clk边缘(之前表示当前clk的前一个clk)的表达式(以$ rose(expr))被采样为'0'(或'x'或'z'),并且它在这个时钟边沿被采样为'1'。$fell,只是相反情况发生。前一个值应该取样为'1'(或'x'或'z')而且当前值为'0'。正如下面的例子所解释的,人们需要了解电平敏感采样与边缘敏感采样之间的差异(图5.1)。

但是,为什么我们称这些函数为“采样值”呢?这是因为它们仅在如上所述在推定区域中的表达式的采样值在两个连续时钟边缘处不同时才被触发。换句话说,$ rose(abc)并不意味着像Verilog中的“posedge abc”。 $ rose(abc)只要abc从0变为1,就不会评估为真。$ rose(abc)仅表示abc在当前时钟边缘(在预定区域)采样为'1',并且在紧接的前一个时钟边缘处(在预定区域中)未采样为'1'。

 还要注意,$rose和$ fall都只能在表达式的最低有效位上才工作。如果在这两个采样值函数中使用总线(矢量),您将很快会看到会发生什么情况。

 5.1 $rose:属性/序列中的边缘检测

                                                     图5.2$rose-基础

在顶部逻辑/时序图中的属性'checkiack'将会(图5.2)PASS,因为'inter'和'iack'信号都满足$rose的要求行为(两个连续clks的值是不同的并且先是'0',然后是'1')。然而,底图中的逻辑失败,因为当$rose(intr)符合$rose的要求时,'iack'不符合。 'iack'在两个时钟沿之间不会从'0'变为'1'。

重要说明:重申以上几点。$rose并不意味着posedge,$fell并不意味着negedge。换句话说,一旦检测到'intr'上的posedge,断言就不会认为$rose(intr)是真的。 $rose()/ $ fell()行为是通过在两个连续的时钟边缘“采样”表达式得出的,并且看看这些值是否相反并符合$ rose()或$ fell()。

换而言之,并发断言​​的基本规定必须在采样边缘对所有内容进行采样。行为基于采样值。

5.1.1边缘检测很有用,因为...

 

                                    图5.3“边缘”检测和性能暗示的有用性

 这是一个非常重要的例子。它解释了使用电平敏感采样值与边沿敏感值之间的差异。两者都是正确的使用,除非你知道什么时候使用。如图5.3所示,电平敏感评估是边缘敏感评估的超集。但是,如果实际上您想要进行边缘敏感性评估,但是您使用对电平敏感的采样,则会降低仿真性能。

在上述属性中,如果您只想检查一旦边缘敏感信号intr被触发, iack就从非活动状态('0')进入活动状态'1'。之后,intr的状态并不重要。如果您的目的是在intr的上升沿一个时钟之后检查的iack边缘,以下是编写该断言的更好方法。

property checkiack;
    @ (posedge clk) $rose(intr) |=[$rose(iack);
endproperty

 但是如果你决定做以下事情(如图5.4所示)?现在你遇到了真正的麻烦。如图5.4所示,由于'intr'是电平敏感的采样,因此当它被采样为高电平时,它将查找边沿敏感的'iack'。但由于'intr'对电平敏感,并且在下一个时钟高时,它将启动一个新线程并检查每个时钟的$rose(iack)。由于iack在第二个线程中没有从'0'到'1',所以属性失败。很有可能你不希望看到这种失败。


                                             图5.4$rose-精细点

 简而言之,就像这些功能看起来那么简单,你必须小心使用它们,并且要记住性能影响(图5.5)。

 5.1.2 $fell:属性/序列中的边缘检测

 

                                                        图5.5$fell-基础

 5.1.3在程序块中的$rose,$fell

 $ rose和$ fell不仅在并发断言中非常有用,而且在顺序性程序块中也非常有用。它们的工作方式与并发断言完全相同。

因为每个断言都需要一个时钟事件(即采样边沿),所以当您在程序代码中使用并发断言,但是没有与它们关联显式的时钟事件时,那么仿真器将在并发断言之前的代码中查找时钟事件。

在图5.6中,$(posedge clk)是前面的时钟事件,作为$ rose(iStreamDone)的采样边缘(例子在图的顶部)。

注意在连续赋值语句中使用$ rose和$ fell。由于连续赋值不能具有边缘行为,因此必须明确为$rose()和/或$fell()指定时钟事件。这是适用于其他采样值函数的相同规则。


                                         图5.6$rose和$fell在程序块和连续赋值

 5.2$stable

 顾名思义,$stable()会寻找它的表达式在两个时钟边(即两个采样边)之间是稳定的。它评估当前时钟边沿的表达式并将其与前一个时钟边沿处的采样值进行比较。如果两个值相同,则检查通过(图5.7)。


                                                                 图5.7$ stable-基础

 请注意在连续赋值语句中使用$ stable。由于连续赋值不能具有边缘行为,因此必须使用$ stable明确嵌入时钟事件。这与适用于其他采样值函数的规则相同。

但是,如果您想检查信号是否稳定超过1个时钟,该怎么办?阅读...... $ past()将解决这个问题。

 5.2.1程序块中的$stable

 正如在$rose()和$fell()中一样,$stable也可以嵌入到过程代码中,并且与属性或序列中的工作方式相同。如上例所示,$ stable在当前和前一个边沿(本例中为posedge clk)中对表达式(本例中为'a'和'b')的值进行采样,以查看表达式的值是否不变。在时间15,'b'已经稳定,在25'a'时间已经稳定,等等(图5.8)。


                                     图5.8程序块中的$stable

 5.3$past

 $ past()是一个有趣的函数。它可以让你追溯过去任意时钟,然后您可以检查'表达式1'是否具有特定的值,在以前的时钟数(严格地说是在时间点之前)。请注意,时钟的数量是可选的。如果你没有指定它,默认情况下是在过去的一个时钟查找'表达式1'。

需要注意的另一个警告是当你在仿真的初始时间刻度中调用$past时,没有足够的时钟去'过去'。例如,您可以指定'a |  - > $ past(b)',并且在时间'0'前提'a'为真。过去并没有时钟。在这种情况下,断言将使用'b'的'初始'值。 'b'的初始值是多少?它不是'初始'块中的那个,它是变量'b'被声明的值(如'logic b = 1'b1;')。在我们的例子中,如果'b'在其声明中未被初始化,断言将失败。如果声明初始值为1'b1,则断言将通过。

 

                                                    图5.9$ past-basics

你也可以通过表达式2'gate'这个检查。图5.9中的例子显示$past如何工作。在这个例子中我们使用了一个门控表达式。它不是图5.10中提到的要求,但它很可能在您的应用程序中需要。如果没有指定表达式2,则不会假定时钟门控。

如果您了解使用门控表达式的$past,那么无需使用它就可以直接理解。


                                         图5.10$past门控表达式

 图5.10断言以下属性

assert property (@ posedge clk) done |-[ lV(mySig,2,enb,lastVal)
$display(….);

 属性LV模拟以下内容

property lV(Sig, numClocks, enb, lastV);
(lastV == $past(Sig, numClocks, enb));
endproperty

 该属性表示在numClocks个过去查看Sig,并查看它是否具有值'lastV',并且仅当‘enb’为高时在开始检查。让我再次强调,当'先行词'为真时,检查门控表达式。当你开始检查时,选通表达式必须为真。许多人似乎错过了这一点。让我们看看将解释这个概念的仿真日志。当我们断言/覆盖属性'lV'(代表最后一个值)以便于参考仿真日志(图5.11)时,前一页的例子在这里重复,设置lastV ='ha。

让我们检查仿真日志仔细看看$past是如何工作的。在时间30,第一次完成= 1,这意味着该属性的先行词是真实的,这意味着该属性被执行。 lV的形式参数被assert语句的实际参数取代。


                                     图5.11$ past-gating表达式仿真日志

 因此,在时间30,属性首先检查门控信号('enb')是否为真实。由于确实如此,该属性现在评估过去mySig 在2个时钟的值。看似它确实是h'a(在仿真日志中的时间10)。该属性通过。

在时间50,done= 1和enb = 1,但在过去2个时钟(在时间30)mySig不等于h'a,属性失败。

在时间80,done = 1,但门控信号'enb'是'0'。这里需要注意的一点是,即使mySig的值在过去两个时钟的确是h'a(时刻60),属性也会失败。这是因为当前时钟的门控表达式enb = 0(当先前'完成'是真的),这时$past()不会自我评估。换句话说,$ past()在以前没有查找mySig 2时钟,而是返回了先前评估的值h'5。该属性将h'5的值与h'a的期望值进行比较并且失败。

在没有门控信号的情况下,只要前提是真实的,该属性将始终进行评估,并在过去查找所需的表达式值N个时钟。

还要注意在$display语句中使用$ past,这是一个过程语句。这是一个出色的调试功能。您可以随时显示过去发生了什么以调试当前的设计状态。

 5.3.1应用程序:$ past()

 

                                                图5.12$past的应用

 图5.12是自我解释。请注意,$ past在图形顶部的应用程序中作为结果使用,并在底部应用程序中用作前项。

 5.3.2$past拯救$fell!

                                             图5.13 $past拯救$fell

 图5.13显示$rose/$fell与$past之间的差异。回想一下,$fell(或者$rose)只会对我们正在评估的表达/信号的LSB进行采样。相反,$past评估整个表达式。因此,如果你想检查(例如)整个'总线'的值,你必须使用$past。如图所示,如果实际上您想要检查整个总线在过去几个时钟的评估值,那么$fell将给出对32位总线“dBus”的错误结果。该图解释了如何使用$ past来解决$fell无法解决的问题。

猜你喜欢

转载自blog.csdn.net/zhajio/article/details/80065443