【IC验证】systemverilog_并行线程(块)
【IC验证】systemverilog_并行线程(块)
- 一.线程
- 1.定义
- 2.线程的特性
- 3.线程的分类
- 二.并行线程
- 1.fork join
- 2.fork join_any
- 3.fork join_none
- 三.几种编译器导致运行结果的差异性
- 1.多重fork join_none
- 2.fork join和fork join_none嵌套的奇怪结果
一.线程
1.定义
独立运行的程序。
2.线程的特性
(1) 每个always过程块和initial过程块都是相互独立的线程,always过程块的线程不会结束,而initial过程块的线程可以结束;
(2)每个线程呈现树状结构,父线程可以开辟多个子线程;
3.线程的分类
(1)串行线程
语法:begin end
特点:串行执行
(2)并行线程
语法:fork join, fork join_any, fork join_none
特点:并行执行
二.并行线程
1.fork join
(1)执行框图
(2)说明
内部各线程并行执行,会阻塞后续线程,内部所有线程执行完毕才会执行后续线程;
(3)例子
module tb1;initial begin$display("@%0t : start",$time);fork #1 $display("@%0t : sentence1",$time);#2 $display("@%0t : sentence2",$time);#3 $display("@%0t : sentence3",$time);join$display("@%0t : end",$time);end
endmodule
结果:
(4)注意
如果并行块内部线程和并行块外的后续线程是同时执行的,编译器一般先顺序执行并行块内的语句,再执行并行块外的语句;
module tb1;initial begin$display("@%0t : start",$time);fork $display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);$display("@%0t : sentence3",$time);join$display("@%0t : end",$time);end
endmodule
结果:
2.fork join_any
(1)执行框图
(2)说明
内部各线程并行执行,会阻塞后续线程,内部最短线程执行完毕后就开始执行后续线程;
(3)例子
module tb2;initial begin$display("@%0t : start",$time);fork #1 $display("@%0t : sentence1",$time);#2 $display("@%0t : sentence2",$time);#3 $display("@%0t : sentence3",$time);join_any $display("@%0t : end",$time);end
endmodule
结果:
(4)注意(不同编译器的差异性
)
如果并行块内部线程和并行块外的后续线程是同时执行的,不同编译器的执行顺序是不一样的;
例子:
module tb2;initial begin$display("@%0t : start",$time);fork $display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);$display("@%0t : sentence3",$time);join_any$display("@%0t : out",$time);$display("@%0t : end",$time);end
endmodule
结果:
Questasim:先把并行块内同一时刻的语句执行完,再执行并行块外的后续语句;
VCS:先执行并行块内的第一条语句,再执行并行块外的后续语句,再执行并行块内的后续语句;
3.fork join_none
(1)执行框图
(2)说明
内部各线程并行执行,不会阻塞后续线程,后续线程和内部线程并行执行;
(3)例子
module tb3;initial begin$display("@%0t : start",$time);fork#1 $display("@%0t : sentence1",$time);#2 $display("@%0t : sentence2",$time);#3 $display("@%0t : sentence3",$time);join_none$display("@%0t : out",$time);$display("@%0t : end",$time);end
endmodule
结果:
(4)注意1(不同编译器的差异性
)
当并行块内部线程和并行块后续线程在同一时刻执行时,实际的执行顺序是:先执行并行块后续线程一直执行到遇到阻塞语句(含#、@、wait)
或调度结束(terminates)
,再执行并行块内部线程。##对于调度结束的解释我目前也不太清楚##
例子:
module tb3;initial begin$display("@%0t : start",$time);fork$display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);$display("@%0t : sentence3",$time);join_none$display("@%0t : out",$time);$display("@%0t : end",$time);#1 $display("@%0t : delay",$time);end
endmodule
结果:
三.几种编译器导致运行结果的差异性
1.多重fork join_none
例子:
module tb4;initial beginfork $display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);join_none$display("@%0t : sentence3",$time);$display("@%0t : sentence4",$time);fork $display("@%0t : sentence5",$time);$display("@%0t : sentence6",$time);join_noneend
endmodule
结果:
Questasim:第一个fork join_none并行块,将initial过程块的begin end作为调度结束标志,所以会先执行后续的线程直到end再执行第一个fork join_none并行块内的线程。
VCS:第一个fork join_none并行块,将第二个fork join_none并行块作为调度结束标志,所以会先执行后续的线程直到将第二个fork join_none并行块再执行第一个fork join_none并行块内的线程,最后执行将第二个fork join_none并行块内的线程。
2.fork join和fork join_none嵌套的奇怪结果
(1)
代码:
module tb5;initial fork$display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);fork $display("@%0t : sentence3",$time);$display("@%0t : sentence4",$time);join_none$display("@%0t : sentence5",$time);#1 $display("@%0t : sentence6",$time);join
endmodule
结果:
Questasim:
VCS:
(2)
代码:
module tb5;initial fork$display("@%0t : sentence1",$time);$display("@%0t : sentence2",$time);fork $display("@%0t : sentence3",$time);$display("@%0t : sentence4",$time);join_none$display("@%0t : sentence5",$time);$display("@%0t : sentence6",$time);join
endmodule
Questasim:
VCS: