[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 속성이 이를 방지하는데 도움 된다.

 

 

  1. @ 연산자 (edge 기준):
    • @ 연산자는 보통 에지(Edge) 기준의 이벤트를 다룰 때 사용된다. 예를 들어 posedge나 negedge에 사용되어 해당 에지에서 이벤트를 트리거한다.
    • wait(@posedge clk)는 clk 신호의 상승 에지를 기다린다.
  2. .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()을 하는 것을 볼 수 있다.

 


 

반응형