Verilog 스케줄링 의미론 이해: 타이밍, 이벤트, 실행 순서
Verilog 설계와 테스트벤치는 일반적으로 always 또는 initial 블록, 연속 할당, 기타 절차적 문장으로 구성된 많은 코드 라인을 가지며, 이들은 시뮬레이션 과정에서 서로 다른 시간에 활성화됩니다.
Verilog 모델에서 신호 값의 모든 변경은 업데이트 이벤트(update event)로 간주됩니다. 그리고 이러한 업데이트 이벤트에 민감한 always와 assign 블록 같은 프로세스들은 임의의 순서로 평가되며 이를 평가 이벤트(evaluation event)라고 합니다. 이러한 이벤트들이 서로 다른 시간에 발생할 수 있으므로, 이벤트 큐(event queues)에 스케줄링하여 시뮬레이션 시간으로 정렬함으로써 올바른 실행 순서를 보장하고 관리하는 것이 좋습니다.
module tb;
reg a, b, c;
wire d;
// 'always'는 'a' 또는 'b'가 업데이트될 때 평가되는 프로세스
// 'a' 또는 'b' 값이 변경되면 '업데이트 이벤트'라 함
// 'a' 또는 'b' 변경으로 'always' 블록이 트리거되면 '평가 이벤트'라 함
always @ (a or b) begin
c = a & b;
end
// 'assign'은 'a', 'b', 'c' 중 하나가 업데이트될 때 평가되는 프로세스
assign d = a | b ^ c;
endmodule
이벤트 큐 (Event Queue)
시뮬레이션 단계는 네 가지 영역으로 분할될 수 있습니다. 활성 이벤트 큐는 현재 시간에 실행되어야 할 프로세스들의 집합으로, 더 많은 프로세스가 활성 또는 다른 이벤트 큐에 스케줄링되게 할 수 있습니다. 이벤트는 어느 영역에든 추가될 수 있지만, 항상 활성 영역에서 제거됩니다.
- 활성(Active) 이벤트는 현재 시뮬레이션 시간에 발생하며 어떤 순서로든 처리될 수 있음
- 비활성(Inactive) 이벤트는 현재 시뮬레이션 시간에 발생하지만, 모든 활성 이벤트 처리 후 처리됨
- 비차단 할당(Nonblocking assign) 이벤트는 이전에 평가되었지만, 모든 활성 및 비활성 이벤트 처리 후 현재 시뮬레이션 시간에 할당됨
- 모니터(Monitor) 이벤트는 모든 활성, 비활성, 비차단 할당 완료 후 처리됨
현재 타임 스텝의 활성 큐 모든 이벤트가 실행되면, 시뮬레이터는 시간을 다음 타임 스텝으로 진행시키고 그 활성 큐를 실행합니다.
module tb;
reg x, y, z;
initial begin
#1 x = 1; y = 1;
#1 z = 0;
end
endmodule
시뮬레이션은 시간 0에서 시작하고, 첫 번째 문장은 시뮬레이션 시간이 1 타임 유닛에 도달하면 실행되어 x와 y에 1을 할당합니다. 이는 현재 시간인 1 타임 유닛의 활성 큐입니다. 시뮬레이터는 다음 문장을 1 타임 유닛 후인 시점에 스케줄링하며, 거기서 z에 0을 할당합니다.
시뮬레이션을 비결정적으로 만드는 원인?
같은 설계와 테스트벤치에 대해 다른 출력을 주는 경합 조건(race conditions)이 시뮬레이션 중에 발생할 수 있습니다. 비결정적 동작의 이유 중 하나는 활성 이벤트가 큐에서 제거되어 어떤 순서로든 처리될 수 있기 때문입니다.