Fork join_none module and program block

Program fkjn;
Initial
Begin

Fork
#10 $display(“x”);
#5 $display(“y”);
#15 $display(“z”);
Join_none
End
Endprogram

Output is nothing displayed

Module fkjn;
Initial
Begin

Fork
#10 $display(“x”);
#5 $display(“y”);
#15 $display(“z”);
Join_none
End
Endmodule

Output :
Y
X
Z

Why and how? Please explain it

In reply to suresh_dve:

From section 24.3 of the LRM:

When all initial procedures within a program have reached their end, that program shall immediately terminate all descendent threads of initial procedures within that program.

In reply to cgales:
Which is one of the many reason I don’t recomend using program blocks. Are Program Blocks Necessary? - Verification Horizons

I recently encountered a similar issue at work, so I came across this post from eight years ago. The difference is that with the same code as yours, vcs compiles and outputs the expected results, but when I put fork join_none in the function and call the function in initial, I get the same simulation results as yours, while in module it outputs normally. You know why?

program test;

  task run;
    #1;
    $display("task thread..");
  endtask

  //task show;
  function void show;
    fork
      run;
    join_none
    $display("show thread");
  endfunction
  //endtask

  initial begin
    show;
    fork
      $display("something");
    join_none
    $display("main");
    //#2;
  end 
endprogram

out:
*…/simv up to date
Chronologic VCS simulator copyright 1991-2018
Contains Synopsys proprietary information.
Compiler version O-2018.09-SP2_Full64; Runtime version O-2018.09-SP2_Full64; Aug 21 22:05 2025
show thread
main
something
$finish at simulation time 0
*

Quite the expected - as @dave_59 explained earlier here - in your example the program end is reached before the simulator had a chance to execute your #1.

Good guidelines:

  1. Avoid program block
  2. Ensure you have a wait at the end of initial-block (inside program if you can’t stick to #1 above)