System Verilog线程——fork join的理解使用

本文详细介绍了SystemVerilog中的线程概念,包括顺序块(begin...end)和并发块(fork...join)。顺序块遵循指令顺序执行,而fork...join则实现语句的并行执行。此外,还提到了fork...join_any和fork...join_none的区别,以及如何通过disable关键字停止进程。文中通过实例展示了各种块的执行行为,强调了并发执行中的竞争条件和不确定性。
摘要由CSDN通过智能技术生成

本文参考绿皮书第七章,线程及其线程间的通信,Verilog HDL A guide to digital design and synthesis 2nd第七章。主要对于begin…end,fork…join等进行简单总结。然后给出相对应的实例进行理解。有问题欢迎同学指出。

概述

在Verilog中,存在组合逻辑与时序逻辑,需要仿真器对于两者进行模拟。因此测试平台需要并发执行某些操作,称之为并发的线程。在verilog中存在begin…end,以及fork…join两中分组方式,用于顺序或者是并发执行。在system vrilog中,引入了fork…join_any以及fork…join_none新的方法用于创建线程。最后解释停止进程。

顺序块与并发块(Sequential and Parallel Blocks)

begin…end块

关键字begin和end用于将语句分组为顺序块。
顺序块具有以下特征:

  • 顺序块中的语句按指定顺序处理。只有在前一条语句完成执行后,才会执行该语句。
  • 如果指定了延迟或事件控制,则该延时或事件与块中的前一条语句完成执行时的模拟时间有关。
    分别举例如下
//案例 1: Sequential block without delay
module
reg x, y;
reg [1:0] z, w;
initial begin
	x = 1'b0;
	y = 1'b1;
	z = {x, y};
	w = {y, x};
end
endmodule

对应案例 1: Sequential block without delay
在这里插入图片描述

//案例2: Sequential blocks with delay.
reg x, y;
reg [1:0] z, w;
initial begin
	x = 1'b0; //completes at simulation time 0
	#5 y = 1'b1; //completes at simulation time 5
	#10 z = {x, y}; //completes at simulation time 15
	#20 w = {y, x}; //completes at simulation time 35
end

对应案例2: Sequential blocks with delay.
在这里插入图片描述
注意这里的仿真时间,对w的赋值时间再35ns处

fork…join块

由关键字fork和join指定的并行块提供了有趣的模拟特征。平行块具有以下特征:
•并行块中的语句并行执行。
•语句的顺序由分配给每个语句的延迟或事件控制来控制陈述
•如果指定了延迟或事件控制,则它与执行块的时间有关进入。
案例1:

module tb();
reg x, y;
reg [1:0] z, w;
initial fork
	x = 1'b0; //completes at simulation time 0
	#5 y = 1'b1; //completes at simulation time 5
	#10 z = {x, y}; //completes at simulation time 10
	#20 w = {y, x}; //completes at simulation time 20
join
endmodule

在这里插入图片描述
注意这里的仿真时间,在20ns已经结束了对w的赋值
案例2:

module tb();
reg x, y;
reg [1:0] z, w;
initial fork
	x = 1'b0;
	y = 1'b1;
	z = {x, y};
	w = {y, x};
join
endmodule

在这里插入图片描述
产生同样波形的原因是存在竞争问题。本例中特意引入了竞争条件。所有语句都在模拟时间0开始。语句的执行顺序未知。如果先执行x=1’b0和y=1’b1,变量z和w将得到值1和2。如果x=1’b0和y=1’b1最后执行,变量z和w将得到值2’bxx和2’bxx。因此,z和w的结果是不确定的,并且取决于模拟器的实现。在模拟时,fork-join块中的所有语句都会立即执行。然而,在现实中,运行模拟的CPU一次只能执行一条语句。不同的模拟器以不同的顺序执行语句。因此,竞争条件是模拟器的限制,而不是fork-join块的限制。

fork…join_any与fork…join_none

前面对于fork的引入是为了更好的理解如下点。
join 父进程会阻塞直到这个分支产生的所有进程结束。
join_any 父进程会阻塞直到这个分支产生的任意一个进程结束。 然后继续执行
join_none 父进程会继续与这个分支产生的所有进程并发执行。在父线程执行一条阻塞语句之前,产生的进程不会启动执行。

简单的测试如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

停止进程disable

关键字disable提供了一种终止命名块执行的方法。disable可用于根据控制信号跳出循环、处理错误条件或控制代码段的执行。禁用块会将执行控制传递给紧随该块之后的语句。对于C程序员来说,这与用于退出循环的break语句非常相似。区别在于break语句只能中断当前循环,而关键字disable允许禁用设计中的任何命名块。
在下面的这个例子中,等待时钟或者是等待到特定信号的下降沿。就会推出这个fork线程。两种写法都是可以的。

task get_payload();
    pkt2cmp_payload.delete();//清除之前缓存的数据
    fork begin : wd_timer_fork
            fork : frameo_wd_timer  
                @(negedge rtr_io.cb.frameo_n[da]);  //这里是第一个线程(thread)
				begin  					//begin...end这里是第二个线程start
                    repeat(100) @(rtr_io.cb);
      	            $display("\n%m\n[ERROR]%t Frame signal timed out!\n", $realtime);
                    $finish;
                end 							//begin...end这里是第二个线程end
            join_any : frameo_wd_timer
            //disable fork;					//等待失败,或者是等到下降沿,推出fork join。执行下面的内容
            disable frameo_wd_timer;		//同disable fork;
         end : wd_timer_fork
    join  

后需要在进行补充吧~

附录

线程与进程的关系

摘自绿皮书第七章绪论注释
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值