12 Mar fork-join and disable fork
BFM(Bus Functional Model), scoreboard 등 testbench를 개발하면서 두 개 이상의 process를 동시에 실행하도록 구성해야 하는 경우가 있다. 간단한 예로, 특정 task를 수행하되 일정 시간이 지나면 timeout이 발생하도록 구현하는 경우 두 개의 process가 필요하다. 이 때 사용할 수 있는 것이 SystemVerilog의 fork
와 join
이다. 이와 더불어 join_any
, join_none
그리고 disable fork
에 대해서도 설명한다.
fork-join
fork
–join
내부에 기술된 각 구문은 별개의 process로 동시에 시작된다. 다음 예는 총 5개의 process가 동시에 시작된다. 이 때 ‘hello’와 ‘world’ 중 어떤 것이 먼저 출력되는지는 알 수 없다. 하지만 ‘foo’가 ‘bar’보다 먼저 출력되는 것은 확실하다.
fork // process 1 $display("hello"); // process 2 $display("world"); // process 3 my_task(); // process 4 begin $display("foo"); $display("bar"); end // process 5 repeat (5) begin #1 my_function(); end join
fork
–join
구문 내부에 기술된 모든 구문이 종료되어야 join
이후에 기술된 구문이 수행된다.
fork #5 $display("@%2t: A", $realtime); #10 $display("@%2t: B", $realtime); join $display("@%2t: C", $realtime);
@ 5: A @10: B @10: C
fork-join_any
fork
–join_any
가 fork
–join
과 다른 점은 내부에 기술된 구문 중 어느 하나라도 종료되면 join_any
이후에 기술된 구문이 수행된다는 점이다.
fork #5 $display("@%2t: A", $realtime); #10 $display("@%2t: B", $realtime); join_any $display("@%2t: C", $realtime);
@ 5: A @ 5: C @10: B
fork-join_none
fork
–join_none
이 fork
–join
과 다른 점은 내부에 기술된 구문의 종료 여부와 관련 없이 바로 join_none
이후에 기술된 구문이 수행된다는 점이다. fork-join_none Gotcha 페이지도 참고하자.
fork #5 $display("@%2t: A", $realtime); #10 $display("@%2t: B", $realtime); join_none $display("@%2t: C", $realtime);
@ 0: C @ 5: A @10: B
disable fork
Process를 강제로 종료해야 할 때는 disable fork
구문을 사용한다. disable fork
사용 시에는 주의가 필요하므로 Safe Use of disable fork 페이지를 참고하자. 먼저 위의 fork
–join_any
예제에 disable fork
를 추가하면 다음과 같은 결과를 얻을 수 있다. join_any
를 사용하였기 때문에 ‘A’를 출력하는 process가 종료되는 시점에 disable fork
가 실행되었고, ‘B’를 출력하는 process는 강제 종료되어 ‘B’가 출력되지 않는 것을 확인할 수 있다.
fork #5 $display("@%2t: A", $realtime); #10 $display("@%2t: B", $realtime); join_any disable fork; $display("@%2t: C", $realtime);
@ 5: A @ 5: C
Summary
join
, join_any
, join_none
의 차이와 정확한 동작을 이해하고 사용하면 다양한 상황에서 매우 유용하게 활용할 수 있는 문법이지만, 그렇지 않을 경우 오히려 큰 혼란을 야기할 수 있으므로 개념을 확실히 잡고 있는 것이 좋다. 마지막으로 fork
–join
과 disable fork
를 활용하여 구현한 timeout 기능을 소개한다.
module top; timeunit 1ns; timeprecision 1ns; bit timeout = 0; initial begin fork my_task(); #100 timeout = 1; join_any disable fork; if (timeout) begin $display("timeout"); $finish; end end task my_task(); #1000; // takes longer than #100 endtask: my_task endmodule: top
References
Jung Ik Moon
Verification Engineer
Unknown
Posted at 23:37h, 13 Septemberfork 를 통해 생성된 ‘그것’ 들을 process 로 봐야할까요 아니면 thread 로 봐야할까요..
IKS
Posted at 23:38h, 13 September제가 위 포스트에서는 전반적으로 process라는 용어를 사용했지만 thread로 대체해도 무방합니다.
일반적인 OS 개념에서는 process는 독립적인 메모리 영역을 할당 받고 thread는 메모리 영역을 공유하는 등의 차이가 있으며 하나의 process가 하나 이상의 thread를 가질 수 있습니다만, SystemVerilog LRM 상에서는 fork-join block을 기술할 때 process와 thread를 모두 혼용하여 사용하고 있으며 크게 차이를 두고 있지는 않습니다.
간단히 말해서 fork 수행 시 여러 process가 생성되고 각 process 내에서 thread가 실행된다고 생각하시면 될 것 같네요.
IKS
Posted at 07:38h, 23 JuneComment disabled due to spam comments.