initial begin
$display("@%0t: start fork ... join example", $time);
#10 $display("@$0t: sequential after #10", $time);
fork
$display("@%0t: parallel start", $time);
#50 $display("@%0t: parallel after #50", $time);
#10 $display("@%0t: parallel after #50", $time);
begin
#30 $display("@%0t: sequential after #30", $time);
#10 $display("@%0t: sequential after #10", $time);
end
join
$display("@%0t: after join", $time);
#80 $display("@%0t: after join", $time);
end
本例中fork...join開了4個線程(即並行運行程序,其中begin...end是順序執行,算作一個線程)。 initial 塊執行結束一共需要10+50+80=140ns。其中打印的順序爲下,在140ns 中全部執行結束。
@0: start fork...join example
@10: sequential after #10
@10: parallel start
@20: parallel after #10
@40: sequential after #30
@50: sequential after #10
@60: parallel after #50
@60: after join
@140: finish after #80
如果替換爲fork...join_any會怎麼樣呢?
initial begin
$display("@%0t: start fork ... join example", $time);
#10 $display("@$0t: sequential after #10", $time);
fork
$display("@%0t: parallel start", $time);
#50 $display("@%0t: parallel after #50", $time);
#10 $display("@%0t: parallel after #50", $time);
begin
#30 $display("@%0t: sequential after #30", $time);
#10 $display("@%0t: sequential after #10", $time);
end
join_any
$display("@%0t: after join", $time);
#80 $display("@%0t: after join", $time);
end
本例中fork...join開了4個線程(即並行運行程序,其中begin...end是順序執行,算作一個線程)。 initial 塊執行結束一共需要10+80=90ns。其中,fork...join_any語句執行完$display("@%0t: parallel start", $time);語句耗時爲0,之後就跳出join_any語句。其中打印的順序爲下,在90ns 中全部執行結束。
@0: start fork...join example
@10: sequential after #10
@10: parallel start
@10: after join_any
@20: parallel after #10
@40: sequential after #30
@50: sequential after #10
@60: parallel after #50
@90: finish after #80
如果替換爲fork...join_none會怎麼樣呢?
initial begin
$display("@%0t: start fork ... join example", $time);
#10 $display("@$0t: sequential after #10", $time);
fork
$display("@%0t: parallel start", $time);
#50 $display("@%0t: parallel after #50", $time);
#10 $display("@%0t: parallel after #50", $time);
begin
#30 $display("@%0t: sequential after #30", $time);
#10 $display("@%0t: sequential after #10", $time);
end
join_none
$display("@%0t: after join", $time);
#80 $display("@%0t: after join", $time);
end
本例中fork...join開了4個線程(即並行運行程序,其中begin...end是順序執行,算作一個線程)。 initial 塊執行結束一共需要10+80=90ns。其中,fork...join_none語句不執行完$display("@%0t: parallel start", $time)直接跳出join_any語句執行$display("@%0t: after join", $time);其中打印的順序爲下,在90ns 中全部執行結束。
@0: start fork...join example
@10: sequential after #10
@10: after join_any
@10: parallel start
@20: parallel after #10
@40: sequential after #30
@50: sequential after #10
@60: parallel after #50
@90: finish after #80
問:如果上述三段代碼都沒有最後一段打印語句:#80 $display("@%0t: after join", $time)。誰可以把之前的句子全部打印完。
本題主要考察initial最後語句執行結束後,程序就刻結束執行。因此,fork...join_any和fork...join_none都沒有機會把全部程序執行完。
在SV 中,當程序中inital塊全部執行完畢,仿真其就推出了 。
如果我們希望等待fork塊中所有的線程執行完畢再退出initial塊,此時使用wait fork語句等待所有子線程結束。
task run_threads;
...
fork
check_trans(tr1); //線程1
check_trans(tr2); //線程2
check_trans(tr3); //線程3
join_none
...
//等待所有的fork中線程結束後在退出task
wait fork;
endtask
停止單個線程
在使用fork...jion_any或者fork...join_none以後,我們使用disable來指定需要停止的線程。
parameter TIME_OUT = 1000;
task check_trans(Transaction tr);
fork
begin
//等待迴應,或者達到某個足底啊延時
fork : timeout_block
begin
wait(bus.cb.addr == tr.addr);
$display("@%0t: Addr match %d", $time,tr,addr);
end
#TIME_OUT $display("@%0t: Error: timeout", $time);
join_any
disable timeout_block;
end
join_none
endtask
其中,fork...join_none線程中間還有一個fork...join_any線程作爲並行的塊。fork...join_any塊中只要 滿足begin...end或者#TIME_OUT中的一個,那麼就會退出(誰先執行完成,就是哪個)。這裏只要其中一個線程執行完畢,自動關閉另一個線程,節約資源。
停止多個線程
disable fork可以停止當前線程中衍生出的所有子線程。
initial begin
check_trans(tr0); //線程0
//創建一個線程來限制disable fork的作用範圍
fork //線程1
begin
check_trans(tr1); //線程2
fork //線程3
check_tans(tr2); //線程4
join
//停止線程1-4,單獨保留線程0
#(TIME_OUT/2) disable fork
end
join
end
disable線程1,以及其衍生出來的線程。
停止多次 調用的任務
如果你給某一個任務或者線程指明標號,那麼當這個線程被調用多次後,如果通過disable去禁止這個線程標號,所有衍生的同名線程都將被禁止。
task wait_for_time_out (int id);
if(id == 0)
fork
begin
#2;
$display("@%0t: disable wait_for_time_out", $time);
disable wait_for_time_out;
end
join_none
fork: just_a_little
begin
$display("@%0t: %m: %0d enteriing thread", $time,id);
#TIME_OUT;
$display("@%0t; %m: %0d done", $time,id);
end
join_none
endtask
該任務只有id=0的時候,等待2ns之後禁止任務線程。
initial begin
wait_for_time_out(0); //Spawn thread 0
wait_for_time_out(1); //Spawn thread 1
wait_for_time_out(2); //Spawn thread 2
#(TIME_OUT*2) $display("@%0t: All done", $time);
end
這裏,wait_for_time_out線程被調用了三次,衍生出了三個線程 。
線程0在#2延時之後禁止了該任務,由於三個線程均是同名線程,因此這些線程都被禁止了,最終也沒有完成。