[SystemVerilog] 시스템 베릴로그의 이벤트, 세마포어 사용법 | @event, wait, semaphore
2024. 6. 20. 22:08ㆍ(System)Verilog 시스템 베릴로그
반응형
event
서로 다른 스레드를 테스트벤치의 이벤트 핸들을 통해 동기화
Verilog에서 "이벤트"는 시간의 흐름을 트리거하는 데 사용되는 특별한 상황을 나타내며, 시뮬레이션 동작을 트리거하거나 조절하는 데 사용된다. (주로 posedge 또는 negedge를 사용한다.)
이벤트의 기초내용을 설명하자면,
event event_a; // 이벤트 "a" 선언
// 트리거.해당 이벤트를 발생시킬 때 사용.
->event_a; // "->" 연산자를 사용하여 트리거.
// a 이벤트가 발생할 때까지 대기
@event_a; // "@" 연산자를 사용하여 이벤트 wait
wait (event_a.triggered); // 위와 같이 event wait (차이점 아래 설명)
@와 .triggered의 차이점
: triggered 상태는 시뮬레이션이 진행될 때까지 전체 시간 단계에서 지속된다
따라서, wait 이벤트와 이벤트 트리거가 동시에 발생하면 race condition이 발생하고 triggered 속성이 이를 방지하는데 도움 된다.
- @ 연산자 (edge 기준):
- @ 연산자는 보통 에지(Edge) 기준의 이벤트를 다룰 때 사용된다. 예를 들어 posedge나 negedge에 사용되어 해당 에지에서 이벤트를 트리거한다.
- wait(@posedge clk)는 clk 신호의 상승 에지를 기다린다.
- .triggered 속성 (level 기준):
- .triggered 속성은 이벤트 객체의 상태를 나타내는데, 이는 에지가 아니라 레벨(상태)에 기반한다. 즉, 이벤트가 특정 레벨(1 또는 0)로 바뀌면 트리거되었다고 판단한다.
- .triggered 속성을 사용하면 에지가 아닌 레벨 기준의 이벤트를 확인할 수 있다.
Semaphore
서로 다른 스레드가 동일한 리소스에 액세스 할 경우 공유 자원에 대한 접근을 조절하기 위한 동기화 도구.
주로 다중 스레드 환경에서 공유 자원에 대한 안전한 접근을 보장하기 위해 사용된다.
세마포어 값:
- 세마포어 값이 양수이면, 해당 개수만큼의 스레드가 세마포어에 접근 가능하다.
- 세마포어 값이 0이면, 해당 스레드는 대기 상태에 들어간다.
- 세마포어 값이 음수이면, 해당 스레드는 대기 큐에 들어가게 되고, 접근 권한을 얻을 때까지 기다린다.
function new() // 세마포어에 할당될 키 수를 지정
// 기본 키 수는 0
// 세마포어 핸들 반환 또는 세마포어를 생성할수 없는 경우 NULL을 반환
task get() // 세마포어에서 얻을 키 수를 지정
// 기본 키 수는 1
// 지정된 수의 키를 사용할 수 있으면 메소드가 반환되고 실행이 계속됨
// 사용할 수 없는 경우 키를 사용할 수있을때까지 프로세스 차단
function void put() // 세마포어에 반환되는 키 수를 지정
// 호출되면 지정된 개수의 키가 세마포어에 반환된다
// 반환되는 기본키 수는 1
function int try_get() // 세마포어에서 얻기 위해 필요한 키 수를 지정
// 지정된 수의 키를 사용 가능 -> 메서드는 1을 반환하고 실행을 계속
// 지정된 수의 키를 사용 불가 -> 메서드는 0을 반환하고 실행을 계속
// 요청된 기본 키 수는 1
세마포어는 직접 코드를 짜고 결과를 보는 게 제일 빠르다.
간단하게 예를 들면,
module sema;
semaphore key;
initial begin
key = new (1);
fork
personA ();
personB ();
#25 personA ();
join_none
end
task getRoom (bit [1:0] id);
key.get (1);
$display("[%0t] 가져감!", $time);
endtask
task putRoom (bit [1:0] id);
key.put (1);
$display("[%0t] 두고감", $time);
endtask
task personA ();
getRoom (1);
#20 putRoom (1);
endtask
task personB ();
#5 getRoom (2);
#10 putRoom (2);
endtask
endmodule
결과는 이런 식으로 나올 것이다.
[0] 가져감!
[20] 두고감
[20] 가져감!
[30] 두고감
[30] 가져감!
[50] 두고감
시간을 유의해서 보면, new(1)을 했기 때문에 get()으로 한 개를 가져가면 남아있는 키가 없기 때문에 더 가져갈 수 없다.
따라서 다시 put()을 할 때까지 기다린 후에 get()을 하는 것을 볼 수 있다.
반응형