在进入到observed区域之后,这一区域是为了属性断言(property assertion)准备的,由于属性中需要监测设计中的变量,且必须等到所有每一个数据对象被赋予最终的数值,所以该区域处在了设计区域之后。这样做的好处可以避免采集到不稳定的变量从而导致错误的属性检查。同时,该区域也同样适用于interface和program中的采样操作,使得采集到的数据是处于该Ts的最终值。
reactive 区域:在经历了数据采样之后,断言语句需要进行属性判断,而同时,该区域如果再次对设计区域中的线网和变量赋值则又会使得被激活的线程被再次迁移到active区域。经历了信号采样之后,处于testbench区域中的线程也会被在该区域执行。
postpone 区域:在分别经历了跟设计与testbench有关的区域之后,当前Ts进入了postponed区域。该区域内的值保持稳定,且应同下一个Ts中preponed的值一致。同时,该区域也作为SV PLI/DPI的回调函数(callback)点,使得在SV外部的调用语言例如C在使用SV变量时仍然可以使用到最新的数值,无论是设计部分还是验证部分。
在对上面各区域做了介绍以后,我们结合着之前阻塞赋值和非阻塞赋值的例子进行分析。在上面阻塞赋值时:
再来看看非阻塞赋值的仿真调度安排
所以非阻塞赋值可以用来避免一些设计中的竞争情况,而这种方式也针对于组合和同步时序逻辑的设计场景。但这种设计技巧在验证领域中仍然受到了不少的挑战:
验证人员在testbench实现中更多地采用软件编程方式,即连续性赋值(continous assignment)而不是阻塞/非阻塞赋值的形式。
验证人员首先并不关心设计行为中可能出现的竞争场景,对他们而言首要的是采集到正确的稳定数值。
SV中的属性/断言需要在一个特定的仿真调度区域采集数据和执行属性检查。
对此,我们可以从下面这个的两个例子观察提到的testbench部分数据采样和执行的部分:
module数据采样示例1
仿真结果:
可以看到DUT与TB的采样均发生在clk1的上升沿,并且均采样到了dut.cnt变化前的数值。用仿真调度时序图来表达,则如下图所示。
DUT和TB对dut.cnt的采样均在active区域发生,所以都采样到了du