目录
线程的使用
标准的Verilog对语句有两种分组方式——使用begin. . .end或fork.. . join。begin...end中的语句以顺序方式执行,而fork...join中的语句则以并发方式执行。
在SystemVerilog 中,当程序中的initial块全部执行完毕,仿真器就退出了。有些线程运行时间比较长,可以使用wait fork语句来等待所有子线程结束。
停止线程
SystemVerilog引入disable fork语句使你能够停止从当前线程中衍生出来的所有子线程。
线程间的通信
事件
Verilog中,一个线程总是要等待一个带@操作符的事件。这个操作符是边沿敏感的,所以它总是阻塞着,等待事件的变化。其他的线程可以通过->操作符来触发事件,解除对第一个线程的阻塞。
可以使用电平敏感的wait (e1.triggered())来替代边沿敏感的阻塞语句@e1。如果事件在当前时间步已经被触发,则不会引起阻塞。否则,会一直等到事件被触发为止。
SystemVerilog中的事件可以像参数一样传递给子程序。
等待多个事件的方法:利用for循环来等待每个事件、对触发事件进行计数。
旗语
旗语有三种基本操作。使用new方法可以创建一个带单个或多个钥匙的旗语,使用get可以获取一个或多个钥匙,而put则可以返回一个或多个钥匙。如果你试图获取一个旗语而希望不被阻塞,可以使用try_get ()函数。它返回1表示有足够多的钥匙,而返回0则表示钥匙不够。
使用旗语时有两个地方需要小心。第一,返回的钥匙可以比取出来的多。第二,当测试程序需要获取和返回多个钥匙时,务必谨慎。假设你剩下一把钥匙,有一个线程请求两把而被阻塞,这时第二个线程出现,它只请求一把﹐那么会有什么样的结果呢?在System Verilog 中,第二个请求get (1)会悄悄地排到第一个请求get (2)的前面﹐先进先出的规则在这里会被忽略掉。
信箱
SystemVerilog中的信箱。从硬件角度出发,对信箱的最简单的理解是把它看成一个具有源端和收端的FIFO。源端把数据放进信箱﹐收端则从信箱中获取数据。信箱可以有容量上的限制,也可以没有。当源端线程试图向一个容量固定并且已经饱和的信箱里放入数值时,会发生阻塞直到信箱里的数据被移走。同样地,如果收端线程试图从一个空信箱里移走数据·它也会被阻塞直到有数据放人信箱里。
信箱是一种对象,必须调用new函数来进行实例化。例化时有一个可选的参数size,用以限制信箱中的条目。如果size是0或者没有指定,则信箱是无限大的,可以容纳任意多的条目。
使用put任务可以把数据放入信箱里,而使用get任务则可以移除数据。如果信箱为满,则put会阻塞;而如果信箱为空,则get 会阻塞。peek任务可以获取对信箱里数据的拷贝而不移除它。
这里说的数据可以是单个的值,例如一个整数,或者是任意宽度的logic。可以在信箱中放入句柄,但不能是对象。缺省情况下,信箱没有类型,所以允许在其中放入任何混合类型的数据。但不要这样做!务必在一个信箱里只放一种类型的数据。
如果不希望代码在访问信箱时出现阻塞,可以使用try_get()和 try_peek ()函数。如果函数执行成功,它们会返回一个非零值,否则返回0。这比使用nurn 函数可靠一些,因为在对信箱实施测量直到下一次访问信箱的这段时间里,信箱中条目的数量可能会发生变化。
缺省情况下,信箱类似于容量不限的FIFO一在消费方取走物品之前生产方可以向信箱里放入任意数量的物品。但是,你可能希望在消费方处理完物品之前让生产方阻塞住,以便使两个线程步调一致。在构造信箱时可以指定一个最大容量。缺省容量是0,表示信箱容量不限。任何大于0的容量便可创建一个"定容信箱”。如果试图往信箱里放入多于设定容量的物品,则put会阻塞,直到从信箱里搬走物品腾出空间。
线程同步的几种方法
定容信箱实现同步
使用事件实现同步
使用事件实现同步
使用信箱实现同步