在Verilog/SystemVerilog中使用fork/join的注意事项

    fork/join是Verilog中常用的语句。该语法在SystemVerilog中添加了join_any和join_none两个关键字,使fork的行为发生了变化。本文将比较全面的介绍fork的用法,其中不使用join_any和join_none关键字的时候,其用法和Verilog中一致。

1. fork块中的begin/end块

    在fork块中,begin和end之间的语句会顺序执行,如果没有begin和end,则各条语句会并发执行。看下面的例子。在fork块中有A、B两个任务,由于fork中么有begin/end块,这两个任务是并发执行的,我们看看打印结果。

module tb(

    );

reg 			sigout=0;

initial begin
	fork 
		A();
		B();
	join

	// $display("Started!!");
	// $display("Finished!!");
end 

task A;
	integer i=0;
	repeat (2) begin
		#10;
		$display("Number %d.", i);
		i+=2;
	end 
endtask : A

task B;
	integer j=1;
	#5;
	repeat (4) begin
		#10;
		$display("Number %d.", j);
		j+=2;
	end 
endtask : B

endmodule

    打印结果如下,输出是从0  1  2  3  5  7。A任务和B任务的前两次repeat输出了0  1  2  3,此时A任务结束,B任务继续输出最后两次repeat的值,即5  7。

    如果将A和B任务用begin/end块包含起来,这两个任务将会顺序执行,输出就会变成0  2  1  3  5  7,即A任务执行并输出完毕后,B任务才开始执行。如下图。

2. join/join_any/join_none

    先看看SystemVerilog 3.1a版对于上述关键字的描述。

    使用join时,该fork块将阻塞进程,直到所有在fork中所有的语句都执行完毕;使用join_any时,该fork块将阻塞进程,直到fork块中任意一个进程结束;使用join_none时,该fork块不会阻塞,并会和其他进程一起并发执行。但是这些并发的进程将在遇到第一个阻塞语句时才开始执行。

    使用join时的用法和Verilog是一致的,不再赘述。

2.1 join_any

    为了测试join_any,把上文的代码修改一下。在fork外加了两个打印语句。

module tb(

    );

reg 			sigout=0;

initial begin
	fork 
		A();
		B();
	join_any

	$display("Started!!");
	$display("Finished!!");
end 

task A;
	integer i=0;
	repeat (2) begin
		#10;
		$display("Number %d.", i);
		i+=2;
	end 
endtask : A

task B;
	integer j=1;
	#5;
	repeat (4) begin
		#10;
		$display("Number %d.", j);
		j+=2;
	end 
endtask : B

endmodule

    以下是打印输出。可以看到,fork阻塞了进程,任务A首先完成,输出了0和2。此时由于A任务结束,fork不再阻塞进程,所以可以看到2输出后,紧接着输出了fork外面的两天打印语句。然后任务B接着输出3 5 7。

2.2 join_none

    首先把用于测试join_any的代码中的join_any修改为join_none,其输出如下。

    两条打印语句Started和Finished首先输出,有点出乎意料。这是由于fork块后面没有任何阻塞语句,而join_none不会阻塞下一条阻塞语句之前的所有进程。由于任务A和B中都添加了延时,所以Started和Finished被首先打印,然后才轮到任务A和B输出。为了更清晰的理解join_none,将测试程序进行修改,添加一个阻塞赋值语句,同时增加输出信号。

module tb(

    );

reg 			sigout=0;
reg 			a_end, b_end;

initial begin
	a_end = 0;
	b_end = 0;
	fork 
		A();
		B();
	join_none
	
	$display("Started!!");
	#20 sigout = 1;
	$display("Finished!!");
end 

task A;
	integer i=0;
	repeat (2) begin
		#10;
		$display("Number %d.", i);
		i+=2;
	end 
	a_end = 1;
endtask : A

task B;
	integer j=1;
	#5;
	repeat (4) begin
		#10;
		$display("Number %d.", j);
		j+=2;
	end 
	b_end = 1;
endtask : B

endmodule

    首先在Started和Finished两条打印语句之间插入了一个赋值语句,同时定义了三个新信号:a_end、b_end、sigout。该程序打印输入如下。fork内部的语句将和#20 sigout = 1之前的语句同时开始并发执行,但是该执行被挂起,直到遇到了#20 sigout = 1之后,才会执行。所以我们看到,Started的打印是0延时的,所以首先输出。接着是输出0和1,然后是20ns之后的sigout有效和Finished打印语句。

    在看输出的波形,sigout和a_end都在20ns时输出,b_end在45ns时输出,符合预期。

 

### 配置 `verilog_systemverilog.vim` 文件 为了优化 VerilogSystemVerilog 的编辑体验,在 `.vimrc` 中添加特定配置是必要的。这不仅能够实现语法高亮,还能增强其他功能如自动补全、语法检查和格式化。 #### 修改 .vimrc 文件 在 `.vimrc` 文件中加入以下内容可以确保 Vim 正确识别并处理不同类型的 SystemVerilog 文件: ```vim augroup filetypedetect au BufNewFile,BufRead *.sv,*.svh,*.svp,*.vh,*.vp setfiletype systemverilog augroup END ``` 上述设置通过关联指定扩展名到 `systemverilog` 类型来触发相应的语法高亮和其他特性[^4]。 #### 安装插件支持 对于更高级的功能需求,安装专门针对 Verilog 及其超集——SystemVerilog 设计的插件是非常有帮助的。推荐使用[Vim Syntax Plugin for Verilog and SystemVerilog][^3]这款插件,它可以极大地提升开发效率,使 Vim 成为一个强大的硬件描述语言开发平台。 #### 自定义 verilog_systemverilog.vim 如果希望进一步自定义 `~/.vim/syntax/verilog_systemverilog.vim` 或者类似的文件路径下的配置文件,则可以根据个人喜好调整颜色方案、关键字列表等参数。下面是一个简单的例子展示如何增加额外的关键字用于更好的语法着色效果: ```vim " ~/.vim/syntax/systemverilog.vim syn keyword svStatement if else case default forever fork join repeat while do begin end module initial always task function wire reg input output inout supply0 supply1 tri pullup pulldown small medium large vdd vss hi def link svStatement Statement ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值