systemVerilog嵌套Fork

systemVerilog嵌套Fork,verilog,system-verilog,hdl,Verilog,System Verilog,Hdl,我遇到了别人写的代码,我不明白它是如何工作的 // Task A task sub_run_a(); while ($time < 50us) begin #1us; $display("sub_run_a(): ping at time %d", $time); end endtask : sub_run_a // Task B task sub_run_b(); #5us; $display("sub_run_b() finished"); e

我遇到了别人写的代码,我不明白它是如何工作的

 // Task A
 task sub_run_a();
    while ($time < 50us) begin
    #1us;
    $display("sub_run_a(): ping at time %d", $time);
  end
endtask : sub_run_a

// Task B
task sub_run_b();
  #5us;
  $display("sub_run_b() finished");
endtask : sub_run_b

// Task C
task sub_run_c();
  #10us;
  $display("sub_run_c() finished");
endtask : sub_run_c
当我看到模拟结果时,似乎所有的任务都并行运行,我不知道发生了什么

任务A不应该在任务B和任务C完成之前启动吗

但事实并非如此,因为这是输出:

# KERNEL: sub_run_a(): ping at time                 1000
# KERNEL: sub_run_a(): ping at time                 2000
# KERNEL: sub_run_a(): ping at time                 3000
# KERNEL: sub_run_a(): ping at time                 4000
# KERNEL: sub_run_b() finished
# KERNEL: sub_run_a(): ping at time                 5000
# KERNEL: sub_run_a(): ping at time                 6000
# KERNEL: sub_run_a(): ping at time                 7000
# KERNEL: sub_run_a(): ping at time                 8000
# KERNEL: sub_run_a(): ping at time                 9000
# KERNEL: sub_run_c() finished
# KERNEL: sub_run_a(): ping at time                10000
# KERNEL: sub_run_a(): ping at time                11000
# KERNEL: sub_run_a(): ping at time                12000
# KERNEL: sub_run_a(): ping at time                13000
# KERNEL: sub_run_a(): ping at time                14000
# KERNEL: sub_run_a(): ping at time                15000
# KERNEL: sub_run_a(): ping at time                16000
# KERNEL: sub_run_a(): ping at time                17000
# KERNEL: sub_run_a(): ping at time                18000
# KERNEL: sub_run_a(): ping at time                19000
# KERNEL: sub_run_a(): ping at time                20000
# KERNEL: sub_run_a(): ping at time                21000
# KERNEL: sub_run_a(): ping at time                22000
# KERNEL: sub_run_a(): ping at time                23000
# KERNEL: sub_run_a(): ping at time                24000
# KERNEL: sub_run_a(): ping at time                25000
# KERNEL: sub_run_a(): ping at time                26000
# KERNEL: sub_run_a(): ping at time                27000
# KERNEL: sub_run_a(): ping at time                28000
# KERNEL: sub_run_a(): ping at time                29000
# KERNEL: sub_run_a(): ping at time                30000
# KERNEL: sub_run_a(): ping at time                31000
# KERNEL: sub_run_a(): ping at time                32000
# KERNEL: sub_run_a(): ping at time                33000
# KERNEL: sub_run_a(): ping at time                34000
# KERNEL: sub_run_a(): ping at time                35000
# KERNEL: sub_run_a(): ping at time                36000
# KERNEL: sub_run_a(): ping at time                37000
# KERNEL: sub_run_a(): ping at time                38000
# KERNEL: sub_run_a(): ping at time                39000
# KERNEL: sub_run_a(): ping at time                40000
# KERNEL: sub_run_a(): ping at time                41000
# KERNEL: sub_run_a(): ping at time                42000
# KERNEL: sub_run_a(): ping at time                43000
# KERNEL: sub_run_a(): ping at time                44000
# KERNEL: sub_run_a(): ping at time                45000
# KERNEL: sub_run_a(): ping at time                46000
# KERNEL: sub_run_a(): ping at time                47000
# KERNEL: sub_run_a(): ping at time                48000
# KERNEL: sub_run_a(): ping at time                49000
# KERNEL: sub_run_a(): ping at time                50000 

外叉同时启动两件事:

  • 副驾驶
  • 内叉
  • 内叉依次同时启动两件事情:

  • 次级运行
  • 次级运行
  • 因此,所有3项任务都同时启动


    同样有趣的是,sub_run_a在内部fork在10us完成后继续显示ping。这可以通过在外拨叉之后使用禁用拨叉来控制。

    内拨叉和sub_run_a位于同一深度,这意味着外拨叉同时启动内拨叉和sub_run_a。然后,内拨叉将继续启动sub_run_b和sub_run_c

    因此,内部fork对进程何时启动没有影响,但它确实具有总体影响。内部fork及其join语句使其能够在sub_run_a进程完成或sub_run_b和sub_run_c进程都完成时,join_any语句将允许主进程继续。如果三个过程中的任何一个都完成了,如果没有内部分叉,外部过程将继续


    如果将$display()语句放在join\u any语句的正后方,并尝试使用内部fork和不使用内部fork运行它,您应该会看到行为上的差异。

    这与
    begin。。。在
    分叉中结束
    。。。加入

    开始。。。以叉子结束。。。加入任何人

    假设您使用了
    begin。。结束
    然后:

    fork 
      begin
        sub_run_c();  
        sub_run_b();
      end
      sub_run_a();
    join_any
    
    fork 
      fork
        sub_run_c();  
        sub_run_b();
      join
      sub_run_a();
    join_any
    
    在这种情况下,外叉。。。join_any将产生2个线程,它将从fork中出现。。。一旦两个线程中的任何一个线程完成,立即加入任意线程

    2个外叉螺纹。。。加入任何-

    • 分包运行a()
    • 开始。。结束(现在开始…结束将按顺序执行两种方法sub_run_c和sub_run_b)
    sub_run_a()和sub_run_c()将同时启动,sub_run_b将在sub_run_c完成后启动

    叉子。。。加入fork。。。加入任何人

    假设您使用了
    begin。。结束
    然后:

    fork 
      begin
        sub_run_c();  
        sub_run_b();
      end
      sub_run_a();
    join_any
    
    fork 
      fork
        sub_run_c();  
        sub_run_b();
      join
      sub_run_a();
    join_any
    
    在这种情况下,外叉。。。join_any将产生2个线程,它将从fork中出现。。。一旦两个线程中的任何一个线程完成,立即加入任意线程

    2个外叉螺纹。。。加入任何-

    • 分包运行a()
    • 叉子。。join(现在fork…join将产生另外两个线程sub_run_c和sub_run_b)
    sub_run_a()、sub_run_c()、sub_run_b()都将同时启动

    在这两种情况下,外叉。。。当任何一个 两个衍生线程中的一个已完成。但是在嵌套的情况下 开始。。。结束时,将使用2个内螺纹(sub_run_c和sub_run_b) 按顺序执行,而对于嵌套的fork。。。连接,2内部 线程将同时执行