본문 바로가기
시스템 반도체/Arm

Arm SWAP Instruction ( 메모리 접근, SWP, MESI protocol, LDREX, STREX )

by 전컴반 2022. 4. 7.
반응형

Memory access 중에 swap instruction을 보자. 

 

SWAP Instruction 

 

swp r0, r1, [r2] 이런 식으로 사용하는데, 동작은 2가지로 나눠 볼 수 있다. 

 

1. r2가 가지고 있는 주소의 데이터를 r0에 저장하고

2. r1의 값을 r2의 메모리 값에 저장한다. 즉 swapping 동작을 수행한다.

 

이런 동작이 왜 필요할까? 자원을 공유하기 위해서이다. 굉장히 중요한 동작인데

예를 들어, 하나의 프린터를 여러 컴퓨터가 공유한다고 할 때, 동시에 사용할 수 없기 때문에 사용 가능한지 안 한지 계속 확인해야 한다. 이런 부분을 확인하려면 메모리에 "Lock"이라는 부분을 확인해야 한다.

 

즉, Lock의 정보를 불러와서 확인하고 업데이트해야 하기 때문에 STR, LDR을 사용해야 는 부분을 SWP 명령어로 묶은 것이다.  

 

예를 보자

Before
mem32[0x9000] = 0x1234_5678
r0 = 0x0000_0000
r1 = 0x1111_2222
r2 = 0x0000_9000

swp r0, r1, [r2]

After
mem32[0x9000] = 0x1111_2222
r0 = 0x1234_5678
r1 = 0x1111_2222
r2 = 0x0000_9000

 

하지만 Arm 7 이후에는 지원하지 않는 명령어인데 이를 LDREX, STREX로 나눠서 동작하게 했다.

 

왜 Arm은 SWAP 명령어를 포기했을까? 

먼저 간단한 배경 지식인 MESI ( Modified Exclusive Shared invalid ) protocol의 이해가 필요하다.

예를 들어보자, 프린터를 사용하기 위해 코어 4개가 모두 swp r0, r1, [r2]을 이용하여 lock을 확인한다고 하자. 

 

 

어떻게 동작하는지 보면,

1. 먼저 cpu0가 메인 메모리의 lock에서 0을 가지고 왔다. 그러면 cpu0는 0을 1로 바꾸고 TAG를 Modified 한다.  

 

2. 다음으로 똑같이 cpu1이 swp명령어를 수행하는데 r1에 대한 request (lock)를 다른 cpu가 가지고 있는지 캐시에서 확인한다. 만약 가지고 있다면 제공해준다. (cache to cache transfer)

 

3. cpu1은 cpu0에서 제공한 lock 정보 ( = 1)를 얻는다. 다른 cpu에서 정보를 shared 한 상태이니 cpu0와 cpu1의 TAG를 Shared로 변경한다.

 

4. cpu1은 얻은 정보인 1을 1로 업데이트한다. 즉, cpu1는 lock 정보를 Modified 하는데 실패한다. 왜냐면 cpu0가 이미 1로 바꿔놨기 때문이다.

 

5. cpu1에서 연산한 데이터( = 1)를 업데이트하기 전에 cpu0에서 공유돼 있던 정보( = 1)를 invalid 처리해야 한다. 왜냐면 혹시 다른 cpu가 변경되기 전의 정보를 request 할 수도 있기 때문이다.

 

6. 이에 Shared로 돼 있던 cpu0의 TAG는 Invalid로 변경되면서 cpu1의 업데이트 정보의 TAG는 Modified로 변경된다. 

 

7. 다른 cpu에서도 반복이다.

 

정리하면 swp을 계속 사용했을 때 문제는 다른 cpu에서 lock을 얻기 위해 계속 swp 명령어를 수행하며 cpu0가 lock을 release 할 때까지 bus의 bandwidth를 낭비하게 된다. 좀 더 자세히 말하면 str동작을 하기 위해 bus를 계속 사용한다는 의미다. 이런 점에서 swp를 사용하지 않고 LDREX, STREX로 나눠서 사용하게 된 것이다.

 

아래처럼 전체를 동작하지 않고 ldrex만 반복적으로 동작하며 확인한다.

lock: 
    LDREX   r1, [r0];   // check if locked
    CMP      r1, #LOCKED
    BEQ      lock

    MOV      r1, #LOCKED
    STREX   r2, r1, [r0]  // attempt to lock
    CMP      r2, #0        // check if strex is successful
    BNE      lock
    DMB
반응형

댓글