**测试平台中的所有线程都需要同步并交换数据。**例如在最基本的层面,一个线程等待另一个,多个线程可能会同时访问同一资源;在最高的层面上,线程间需要彼此交换数据。
systemverilog线程间的通信有三种:
1)事件 event
在verilog中,当一个线程在一个事件上发生阻塞的同时,正好另一个线程触发了这个事件,则竞争的可能性便出现了。如果触发线程先于阻塞线程,则触发无效。systemverilog引入了triggered()函数,可用于查询某个事件是否触发,包括在当前的时刻。线程可以等待这个函数的结果,而不用在@操作符上阻塞。
等待事件的触发:@event wait(a.triggered())
事件的边沿触发:->event
这个可以参考我之前写的文章:systemverilog中@和wait的区别
2)旗语 semaphore
旗语可以视为一个互斥体,用于实现对同一资源的访问控制。
旗语有三种基本操作。
一是使用new方法可以创建一个带单个或多个钥匙的旗语;
semaphore sem;
sem = new();等价于sem=new(0) ; //相当于没有钥匙
sem = new(2); //相当于两个钥匙
二是使用get() 可以获取一个或多个钥匙;
如果你试图获取一个旗语而不希望被阻塞,可以使用try_get()函数,返回1足够多,返回0表示不够
三是使用put()则可以返回一个或多个钥匙;
3)信箱 mailbox
用于两个线程间传递信息。从硬件的角度看,对信箱的简单理解为具有源端和收端的FIFO。
信箱是一种对象,必须调用new()函数来实例化,
mailbox mb;
如果要显示的限定mailbox中的类型,可以通过mailbox #(type = T)的方式类声明,例如mailbox #(int);
mb = new()等价于mb=new(0) //无限大的空间
mb = new(2);
mailbox的基本操作:
1、将信息放入邮箱:put()阻塞方法
非阻塞性将信试着放入邮箱: try_put()非阻塞方法
2、从邮箱中取出信息:get()阻塞方法
非阻塞性从邮箱中取出信息:try_get()非阻塞方法
3、数据拷贝而不移除: peek() 阻塞方法
非阻塞性数据拷贝而不移除: try_peek()非阻塞方法
4、获取邮箱中的信息的数量:num()
使用mailbox中的阻塞方法时不一定会立刻返回,而队列中所对应的方法push_back和pop_front时非阻塞的,会立刻返回。因此在使用queue时需要额外填写wait(queue.size()>0)
如果调用阻塞方法,则只能在task中调用,调用非阻塞方法,则可以在task和function中调用。