-
Verilog Simulation 이해하기 - Non-blocking과 Blocking assigment의 순서Tech/Verilog 2013. 10. 8. 20:10
Verilog Simulation은 Cycle-accurate Simulation이 가능하다는 장점이 있는 반면, 같은 time step T에 해당하는 모든 event가 동시에 수행된다는 점에서 복잡하기도 하다. 특히 순차적으로 동작하는 blocking statements와 동시에 동작하는 non-blocking statement가 섞여있으면 누가 더 먼저 실행되나? 헷갈리게 된다. 이렇게 Verilog Simulation 상의 Event 처리 순서가 궁금할 때, Verilog Simulation Refernce Model을 참조해서 읽어보면 애매한 부분들이 어느정도 해결된다.
본 포스팅에서는 바로 그 Verilog Simulation Reference Model 및 동작 순서에 대해서 간략히 정리하려고 하는데, 더 자세히 알고 싶다면 아래 Article을 참조하면 된다.
Clifford E. Cummings, “Verilog Nonblocking Assignments With Delays, Myths & Mysteries”, SNUG 2002.
Verilog Simulation Reference Model
Verilog Simulation은 Cycle-accurate하게 동작하기 위해서 Simulation Time에 따라 동일한 Time에 발생하는 Event를 한꺼번에 큐에 넣은 뒤에 하나씩 처리하는 방식으로 진행된다. Simulation이 시작하면, 시간 T는 0, 모든 net은 HiZ, 모든 변수는 X (unknown)로 설정된 뒤, initial이나 always 등의 procedural block이 active되면서 이벤트를 처리하기 시작한다. Pseudo-code형태로 표현하면 아래와 같다.
while (there are events) { // 이벤트가 있다면 if (there are active events) { // Active event 가 있다면, E = any active event; // Active event를 E라 하자. if (E is an update event) { // E가 상태 업데이트 이벤트라면 update the modified object; // 상태를 업데이트 하고, add evaluation events for sensitive processes to event queue; // 업데이트된 변수에 sensitive한 procedure를 // event queue에 추가한다. } else { // E가 상태 업데이트 이벤트가 아니라면, evaluate the process; // 수행하고, (combinational 연산의 경우에 해당) add update events to the event queue; // 상태 업데이트 이벤트로 추가한다. } } else if (there are nonblocking update events) { // Nonblocking 으로 상태 업데이트 // 이벤트가 있다면 (<= 대입의 경우) active all nonblocking update events; // 모두 update event queue로 추가하고 } else { advance T to the next event time; // 다음 Time step T로 이동 activate all inactive events for time T; // T에 해당하는 event는 모두 Active시킨다. } }
그림으로 그려보면 아래와 같이 나타난다.
정리해보면 Verilog Simulation에서는
- =를 이용해 대입한 Blocking assignments
- 대입문에서의 Right Hand Side (A<=B+C라 하면 B+C 에 해당하는 combinational logic)
- assign D = E 에 해당하는 Continuous assignment
- 그리고 $display 명령어
가 가장 먼저 실행되며, (이 때, 이들 4가지의 서로 간 실행 순서는 상관없다.) 그 뒤로
- <=로 대입되는 Nonblocking assignment
의 업데이트가 이루어진다. 이 때, Nonblocking으로 업데이트되는 변수에 관계있는 Event들은 추가적으로 Active Event로 등록된다. Event Queue는 이렇게 추가된 Event들까지 모두 처리한 이후에, 더이상 queue에 event가 남아있지 않을 때 종료되며, 최종적으로는 아래 2가지 명령어를 처리하고 다음 Time step으로 이동한다.
- $monitor, $strobe
따라서, Verilog Simulation에서 Non-blocking 등으로 대입한 변수의 변화를 확인하고자 한다면 $monitor를 써야한다. 몇가지 추가적인 예제를 보면서 이 순서를 이해해보자.
Verilog Simulation에서 헷갈리기 쉬운 몇가지 예제들
module display_cmds; reg a; initial $monitor(“\$monitor: a = %b”, a); initial begin $strobe (“\$strobe : a = %b”, a); a = 0; a <= 1; $display (“\$display: a = %b”, a); #1 $finish; end endmodule
위 결과가 어떻게 출력될까? 아래와 같이 나타난다.
$display: a = 0 $monitor: a = 1 $strobe : a = 1
앞서 이야기했듯이, $display는 Nonblocking assignment에 앞서 수행되기 때문에 a 값이 미처 업데이트되지 않았다.
module nb_schedule1; reg a, b; initial begin a = 0; b = 1; a <= b; b <= a; $monitor $display $strobe #0 $display #1 $monitor $display $strobe $display #1 $finish; end endmodule
이 예제는 결과가 어떻게 출력될까? #0 와 같이 다소 tricky한 문법이 사용되었는데, 위 Simulation Model 대로만 해석하면 된다. 본 예제를 통해, #0를 사용한다고해서 blocking assignment의 가장 마지막에 동작한다거나 하는 효과를 얻을 수 없음을 알 수 있다. 결과 콘솔은 아래와 같이 나타난다.
0ns: $display: a=0 b=1 0ns: #0 : a=0 b=1 0ns: $monitor: a=1 b=0 0ns: $strobe : a=1 b=0 1ns: $display: a=1 b=0 1ns: #0 : a=1 b=0 1ns: $monitor: a=1 b=0 1ns: $strobe : a=1 b=0
즉, Verilog Simulation에서 non-blocking assignment는 모든 active event가 수행된 뒤에 일어나기 때문에, $display가 먼저 실행된다. 따라서 $display로는 Nonblocking assignment의 업데이트 결과를 볼 수 없으며, Nonblocking assignment를 사용해서 대입 된 변수는 $monitor 를 통해서 확인하도록 하자.