2

Overview

fork...join结构提供了创建并行进程的能力。在Systemverilog里主要有三种版本:

  • fork...join (join all)
  • fork...join_none
  • fork...join_any

fork-join同verilog里面的功能是一样。
fork-join_none不会等创建的进程完成,直接执行后面的语句。
fork-join_any会等待至少一个进程完成,然后再执行后继的语句。

Example

Basic

SV code

//
// Created by        : Harris Zhu
// Filename          : test.sv
// Author            : harriszhHarris
// Created On        : 2017-11-09 07:54
// Last Modified      : 
// Update Count      : 2017-11-09 07:54
// Tags              : fork join 
// Description        : 
// Conclusion        : 
//=======================================================================
//                      

`timescale 1ns/1ns

module test;
string testname;

initial
begin
    $timeformat(-9, 0, "ns", 4);
    if($value$plusargs("TEST=%s", testname))
    begin
        $display("TESTNAME=%s", testname);
    end
    
    if(testname=="ALL")
    begin
        fork
            send(7);
            send(5);
            send(2);
        join
        $display("come out of fork-join @%t", $time);
        #100;
        $finish;
    end
    if(testname=="NONE")
    begin
        fork
            send(7);
            send(5);
            send(2);
        join_none
        $display("come out of fork-join_none @%t", $time);
        wait fork;
        $display("wait fork returned @%t", $time);
        #100;
        $finish;
    end
    if(testname=="ANY")
    begin
        fork
            send(7);
            send(5);
            send(2);
        join_any
        $display("come of of fork-join_any @%t", $time);
        wait fork;
        $display("wait fork returned @%t", $time);
        #100;
        $finish;
    end
end

task automatic send(int j);
begin
    #(j);
    $display("driving port %0d @%t", j, $realtime);
end
endtask // send

endmodule

makefile

SIM=irun
SIMOPTS=-sv
SRC=test.sv
run: all

all:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=ALL -log $@.log
    
none:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=NONE -log $@.log

any:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=ANY -log $@.log

Run

  • make all
TESTNAME=ALL
driving port 2 @ 2ns
driving port 5 @ 5ns
driving port 7 @ 7ns
come out of fork-join @ 7ns
Simulation complete via $finish(1) at time 107 NS + 0
./test.sv:40        $finish;

fork-join等到最后一个进程退出才返回

  • make any
TESTNAME=ANY
driving port 2 @ 2ns
come of of fork-join_any @ 2ns
driving port 5 @ 5ns
driving port 7 @ 7ns
wait fork returned @ 7ns
Simulation complete via $finish(1) at time 107 NS + 0
./test.sv:66        $finish;

fork-join_any在第一个进程完成后就返回了

  • make none
TESTNAME=NONE
come out of fork-join_none @ 0ns
driving port 2 @ 2ns
driving port 5 @ 5ns
driving port 7 @ 7ns
wait fork returned @ 7ns
Simulation complete via $finish(1) at time 107 NS + 0
./test.sv:53        $finish;

fork-join_none直接返回,没有等任何进程完成

Advance

在使用fork...jone的时候,我们往往还会和for loop一起使用,因为语言的问题,其实大部分人都会范错误,主要集中在对for循环里的index使用上,另外就是在wait使用上,具体见下文。

SV code

/
// Created by        : Harris Zhu
// Filename          : test.sv
// Author            : harriszhHarris
// Created On        : 2017-11-09 07:54
// Last Modified      : 
// Update Count      : 2017-11-09 07:54
// Tags              : fork join 
// Description        : 
// Conclusion        : 
//=======================================================================
//                      


module test;

string testname;

initial
begin
    $timeformat(-9, 0, "ns", 4);
    if($value$plusargs("TEST=%s", testname))
    begin
        $display("TESTNAME=%s", testname);
    end
end

initial
begin
    if(testname=="ALL")
    begin
        for(int i = 0; i < 16; i++)
        begin
            fork 
                automatic int index =i;    
                send(index);
            join 
        end
        $display("fork-join return @%t", $time);
        #100;
        $finish;
    end
    if(testname=="NONE")
    begin
        for(int i = 0; i < 16; i++)
        begin
            fork 
                automatic int index =i;    
                send(index);
            join_none 
        end
        $display("fork-join_none returned @%t", $time);
        wait fork;
        $display("wait-fork returned @%t", $time);
        #100;
        $finish;
    end
    if(testname=="ANY")
    begin
        for(int i = 0; i < 16; i++)
        begin
            fork 
            begin
                automatic int index =i;    
                send(index);
            end
            join_any 
        end
        $display("fork-join_any returned @%t", $time);
        wait fork;
        $display("wait-fork returned @%t", $time);
        #100;
        $finish;
    end
end

task automatic send(int j);
begin
    #(j);
    $display("driving port %0d %t", j, $realtime);
end
endtask // send

endmodule

makefile

SIM=irun
SIMOPTS=-sv
SRC=test.sv
run: all

all:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=ALL -log $@.log
    
none:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=NONE -log $@.log

any:
    ${SIM} ${SIMOPTS} ${SRC} +TEST=ANY -log $@.log

Run

  • make all
TESTNAME=ALL
driving port 0                    0
driving port 1                    1
driving port 2                    3
driving port 3                    6
driving port 4                  10
driving port 5                  15
driving port 6                  21
driving port 7                  28
driving port 8                  36
driving port 9                  45
driving port 10                  55
driving port 11                  66
driving port 12                  78
driving port 13                  91
driving port 14                  105
driving port 15                  120
fork-join return @                120
Simulation complete via $finish(1) at time 220 NS + 0
./test.sv:41            $finish;
  • make any
TESTNAME=ANY
driving port 0                    0
driving port 1                    1
driving port 2                    3
driving port 3                    6
driving port 4                  10
driving port 5                  15
driving port 6                  21
driving port 7                  28
driving port 8                  36
driving port 9                  45
driving port 10                  55
driving port 11                  66
driving port 12                  78
driving port 13                  91
driving port 14                  105
driving port 15                  120
fork-join_any returned @                120
wait-fork returned @                120
Simulation complete via $finish(1) at time 220 NS + 0
./test.sv:73            $finish;
  • make none
TESTNAME=NONE
fork-join_none returned @                  0
driving port 0                    0
driving port 1                    1
driving port 2                    2
driving port 3                    3
driving port 4                    4
driving port 5                    5
driving port 6                    6
driving port 7                    7
driving port 8                    8
driving port 9                    9
driving port 10                  10
driving port 11                  11
driving port 12                  12
driving port 13                  13
driving port 14                  14
driving port 15                  15
wait-fork returned @                  15
Simulation complete via $finish(1) at time 115 NS + 0
./test.sv:56            $finish;

从上面结果看, 只有join_none实现了并行
原因是顺序的fork...join块还是顺序执行的
同时要注意在fork..join里不要有begin...end

for(int i = 0; i < 16; i++)
begin
    fork 
        automatic int index =i;    
        send(index);
    join_none 
end

自动变量的创建和初始化是在执行和它们位于同一block内的任何过程语句之前

对于wait fork的使用要注意,它是等待当前进程的所有子线程。
所以为了避免有副作用,要像如下这样写

fork
  some_other_process;
join_none
fork 
begin : isolation_process
    for(int j=1; j <=3; ++j) begin : for_loop
      fork
        automatic int k = j;
        begin
            .... # use k here
        end
      join_none
    end : for_loop
  wait fork; // will not wait for some other process
end :isolation_thread
join

summary

总体来说,三种形式各有用处,但在绝大多数情况下又可以用其中一种实现其他两种。 但在fork-join_none的应用范畴更广一些,在并行进程数不定的情况下需要用它才能实行并行。
有任何问题和建议,欢迎发信给作者一起探讨


harriszh
338 声望131 粉丝

做些有趣的事,留些有用的存在


引用和评论

0 条评论