systemVerilog中的event到底怎么回事儿
在SystemVerilog构建测试平台时,经常会用到event来实现多个进程之间的同步处理,例如一个进程处于等待某事件发生,当该事件发生了那么对应的进程将会被执行。但是有时候我们会遇到明明已经触发了事件,为什么对应的进程还处于挂起等待状态呢?本文将示例说明其中原因。
event实际上是一个静态对象句柄指向一个同步的对象,当有进程等待一个某个事件时,这个进程就会被放入这个同步对象中的一个队列中,对于一个事件实际上是可以有多个进程对于这个事件处于一种等待的状态。那么如何让一个进程对于一个事件处于挂起等待状态呢?在SystemVerilog中可以通过@和wait来实现对于事件的等待。
具体触发和阻塞使用方式如下:
触发线程: -> event_name;
首先,我们先了解下触发事件的方式有哪些。常用的事件触发方式有两种,一种是经常用到的”->”,一种是”->>”,其中”->”直到触发成功才会执行该语句下面的语句,而”->>”不对等到event触发了才执行其后的语句。
示例中13行等待5个时间单位后使用”->”触发flag1,其后的语句在触发了flag1后才执行,即”->”阻塞了其后语句的执行。18行使用”->>”触发flag2,此时有个前提是flag1触发,即flag1先于flag2触发,但是19行的执行并没有等待”->>”触发完flag2后才执行,即18行的”->>”操作并没有阻塞其后语句的执行。”->>”除了这个特点外,其在time-slot中执行的区域也与”->”不同,”->>”执行于NBA(Non-Blocking Assignment Region)区,晚于@(flag)操作,所以当”->>”触发事件时,@(flag)挂起可以捕获到触发的事件。
【示例】
而如果将@(flag)置于program中,那么此时的@(flag)挂起等待时间位于NBA操作之后的program区,而触发操作类似于时钟上升沿一样是一个”脉冲”式的行为,过了这个村就没有这个店,即触发先于挂起等待执行的话,那么挂起将会一直阻塞。
【示例】
示例中,14行的触发操作发生于time-slot中的NBA区,此时事件flag句柄指向的同步对象的队列中还没有等待事件存在,所以此时不会处理任何挂起等待的事件。而当前时间槽执行的program所在区域时,”->>”已经执行完毕,所以不会处理@挂起的事件。
以上是和”->>”的一些差异,在实际使用过程中,”->”是经常会被用到的,下面我们以”->”为例,介绍如何等待事件的发生。常用的等待时间发生的方法如下:
Ø 使用@操作符;
Ø 使用wait()方法;
1 “@”操作符
“@”操作符用于挂起等待某个事件的发生,其格式如下:
@(event_name);
但是在使用时必须要注意,“@”操作要先于事件触发操作,否则“@”操作不会捕捉到触发事件。因为如果“@”操作晚于触发操作时,触发操作发生时,会在其指向的同步静态对象的队列中查询不到有挂起等待,就不会解除对应的“@”操作。
【示例】触发操作先于“@”操作发生
示例中,在#9处触发了事件flag,但是此时flag指向的静态同步对象队列中并没有关于flag的等待事件,并且”->”是”一瞬间”执行的,在#10时,此时触发操作早已结束,所以该等待操作将不会被”解禁”。
【示例】触发操作先于“@”操作发生
2 wait()方法
wait()方法用于等待其中参数列表中的事件触发,其使用格式如下:
wait(event_name.triggered);
wait(event_name.triggered)用于检测当前time-slot结束之前是否事件已经发生,它与@操作符的区别是在同一个time-slot中,@操作符可能会错过触发操作,如下例。
【示例】
为此,在等待事件触发时,使用wait(event_name.triggered)的方式,这样可以确保事件触发可以有效地被捕获。
【示例】
示例中,触发事件被flag.triggered被有效捕获。当时在这里使用时必须要注意以下两点:
wait(event_name.triggered)中的triggered不是个方法,是属性,所以这里不能在triggered后加一对括号。
3 wait_order()
wait_order()用来构造将阻塞该进程,直到按照其后括号中参数给定的顺序(从左到右)触发所有指定的事件。无序的事件触发器将不会解除对进程的阻塞。
【示例】
【仿真结果】
示例中,wait_order只有在flag1、flag2和flag3按照其在wait_order括号中的顺序依次触发,wait_order等待才会解除阻塞。如果触发顺序与wait_order括号中的顺序不同,那么wait_order保持阻塞。
【示例】
此时仿真时,仿真器会报错。如果不想让仿真停止下来,但是又能报错mismatch的消息,此时可以使用wait_order...else...结构,当触发事件的顺序与wait_order中的顺序不一致时,会执行else分支之后的语句。
【示例】
示例中,事件出发的顺序与wait_order(flag1,flag2,flag3)不一致,此时wait_order不会阻塞,会执行其后的else分支,从而也不会使其后续程序一致阻塞。
综上示例,@和wait都可以有效的阻塞事件,如果触发线程和阻塞线程在同一时刻发生,则使用wait(event_name.triggered)的线程会被触发,结束阻塞,而使用@event的线程则不会被触发,处于阻塞状态。