
线程是指程序能够独立运行的最小单位,在verilog中有两种形式,分别为begin end 和fork join,SV在这基础上新增了两种类型,为fork join_any和fork join_none。
二、fork join、 fork join_any和fork join_none的区别?fork join:块内语句并行执行,且需要每一个语句块都执行完毕才能继续往下执行。
fork join_any:块内语句并行执行,其中有任何一个语句块执行完毕就会执行下面的内容,不会等 fork join_any中所有语句执行完才往下执行。
fork join_none:不会等任何一个语句块执行完毕就会继续续往下执行,类似于“点火”。
三、wait fork 与 disable forkwait fork:当使用fork join_none时,有可能出现这一种情况是initial begin end里语句都执行万了,仿真都退出了,但是fork join_none里的进程还没有执行完,这个时候可以在等其他程序执行完了的最后加一个wait fork来等待fork join_none里面的线程执行完毕,如下所示:
task ....();
fork
......; //线程A
......; //线程B
......; //线程C
join_none
......; //其它任务
......;
wait fork;
endtask
disable fork:主要用于停止线程,可以停止单个及多个线程。
四、线程及线程间的通信 1、事件(event)event可用于实现线程的同步,通过->操作符来触发事件,通过@和wait来等待事件。在这当中,@为边沿敏感型,可能出现因事件已经被触发而被阻塞住的情况,而wait(xx.triggered)则是电平敏感,如果当前事件已经被触发也不会被阻塞,实例见下:
可以看到,第二个模块中因为阻塞在事件e1上因而没有触发成功(错过了事件触发)。
使用wait(xxx.trigered)则不会出现这种情况,因为系统会检查该事件是否被触发过,从而不用担心因错过事件而被阻塞的情况。
同时,event还可用于事件的传递,主要用法就是在task中任务发送完毕后加一个->event,而在另一个模块中,引用该task,再后面加一个wait(event.triggered)。
2、旗语(semaphore)旗语可以实现对同一资源的控制访问,当一个资源存在多个请求时,可通过semaphore的方式来分配“钥匙”来控制多方的访问请求。在目前世界情况中,本人使用semaphore的地方还特别少,以后用到再更新。
3、信箱(mailbox)在使用sv搭建验证环境时,mailbox的使用还是比较普遍,主要用于各个组件之间的通信(及信息传输),具体用法如下:
如上实现了从 classA中随机产生data,并通过mailbox将值传递给classB的一个过程,用到了了mailbox get /put ,需要注意一点mailbox也需要new函数来开辟存储空间,这一点经常忘记。
mailbox相当于一个fifo的功能,其容量可以使固定的也可以是不固定的,而对于信箱的同步,可以在信箱中使用事件来完成