출처 : 디지털 동호회
----------------------------------------------------------------------
ARM7 강좌 [5] : Exception(1)
----------------------------------------------------------------------
* Exception
우선 Exception이 무엇을 말하는지부터 정리해 보고자 합니다. 일반적으
는 인터럽트와 유사한 개념으로 사용합니다. 어떻게 보면 인터럽트 보다
는 조금 큰 개념이랄 수도 있고, 정확한 정의에 대해서는 말씀을 드리지
못하겠군요. 개념을 ARM7에서의 Exception으로 한정해서 말씀드리겠습니
다.
구체적으로 ARM7에는 FIQ(Fast Interrupt reQuest)와 IRQ(Interrupt reQu-
est), Abort, Software Interrupt, Undefined Instruction Trap 의 5가지
Exception이 있고, 각각 Exception이 발생하면 CPU는 대응하는 동작모드
로 전환됩니다. 여기에 보통 동작상태인 User 동작모드가 추가되어 동작
모드는 총 6개가 있습니다.
- IRQ
: 일반적으로 I/O 장치로부터의 입력이 들어오면 반응을 하는 흔히 말
하는 인터럽트 Exception입니다. IRQ의 종류로는 내부 타이머나 시리
얼, 혹은 외부 IRQ입력 등이 될 수 있습니다.
- FIQ
: 개념적으로는 IRQ와 거의 유사한데, 다만 보다 빠른 처리를 할 수 있
도록 제공되는 Exception입니다. IRQ의 소스는 대부분 FIQ로도 맴핑
될 수 있습니다. 즉, 타이머 인터럽트를 IRQ로 처리하거나, 혹은
FIQ로 처리할 수도 있다는 의미입니다.
- Abort
: CPU가 메모리로부터 인스트럭션을 가져오거나, 혹은 인스트럭션을 동
작시키면서 데이터를 가져오려고 할 경우, 해당 메모리를 억세스 할
수 없다면 AbortException이 발생합니다. 위에 제시한 두가지 경우
에 대응하여 Prefetch Abort와 Data Abort로 구분할 수 있습니다.
- Software Interrupt
: 프로그램에서 임의로 인터럽트를 호출하는 경우입니다. ARM 인스트럭
션 SWI 가 이에 해당합니다. 이 Exception이 발생하면 CPU동작모드가
Supervisor 모드로 바뀌도록 되어 있고, 보통 OS의 시스템 Call을 구
현하기 위해 사용됩니다.
- Undefined Instruction Trap
: ARM7 에 정의되어 있지 않은 명령어를 만났을 경우 발생하는 Except-
ion입니다. 이 기능은 코프로세서를 사용하는 경우와 관련되어 사용
된다고 합니다.
위에서 언급한 5종류의 Exception에 몇가지를 더하여, 해당 처리를 위해
ARM7은 0번지에 벡터 테이블을 유지합니다. 즉, 해당 Exception이 발생하
면 정해져 있는 벡터 번지로 실행을 옮깁니다. 해당 번지는 다음과 같습
니다.
Address Exception Mode on entry
-----------------------------------------------------
0x0000.0000 Reset Supervisor
0x0000.0004 Undefined Instruction Undefined
0x0000.0008 Software Interrupt Supervisor
0x0000.000C Abort(prefetch) Abort
0x0000.0010 Abort(data) Abort
0x0000.0014 --reserved-- --
0x0000.0018 IRQ IRQ
0x0000.001C FIQ FIQ
한가지 주의할 점은 8086의 경우엔 해당 벡터에 ADDRESS를 넣어 두면, 인
터럽트 발생시에 해당 주소를 가져다가 PC에 넣어주는 일이 발생하지만,
ARM7의 경우엔 그냥 해당 벡터로 점프를 합니다. 예를 들어 IRQ가 발생했
다면 다음순간의 pc(r15)값은 0000.0018 이 됩니다. 따라서 해당 벡터 번
지에는 단순히 번지가 들어가는것이 아니라 점프명령 같은것이 들어갑니
다.
* 동작모드
위의 Exception과 관련되어 CPU의 동작모드 몇 가지가 나타나 있습니다.
전에도 몇번 말했듯이 ARM7에는 6가지의 동작 모드가 있습니다. 해당 모
드는 User Mode, FIQ Mode, IRQ Mode, Supervisor Mode, Abort Mode,
Undefined Mode 등의 6가지 입니다.
- 동작모드와 범용 레지스터
동작모드가 왜 있는걸까요? ARM7은 각 동작모드에 따라서 몇가지 기능
을 제공합니다. 가장 큰 것으로 레지스터를 리맵핑시키는 기능이 있습
니다. 좀 다르게 설명하면, 각 모드마다 전용 레지스터가 따로 있다고
도 표현할 수 있겠는데요, 차근차근 설명해 보도록 하겠습니다.
CPU의 동작모드는 보통때는 User 모드 입니다. 이 때는 기본적으로 r0
에서 r15 까지를 사용하고 있겠죠. 그러다 가령 FIQ가 발생했다고 치면
동작 모드가 FIQ 모드로 바뀌게 됩니다. 이와 동시에 r8 부터 r14 까지
의 7개의 레지스터는 FIQ 전용 레지스터로 리맵핑 됩니다. 즉, User모
드의 레지스터와는 별개였던 레지스터 7개가 r8부터 r14까지의 위치에
배치되는 것이죠. 물론 기존의 User모드에서 사용하던 r8-r14까지의 레
지스터와는 별개의 레지스터 입니다.
이렇게 하는 장점을 생각해 보겠습니다. 흔히 인터럽트 처리루틴을 작
성할 경우 인터럽트 발생시 가장먼저 하는일이 사용중이던 레지스터를
스택에 저장하고, 또 처리루틴이 종료될 때는 다시 복구시키는 일이었
습니다. 그러나 ARM7에서 FIQ의 경우를 살피면, FIQ 처리 루틴의 코딩
시에는 r8부터 r14까지를 자유롭게 사용할 수 있고, 또 저장과 복구과
정을 생략해도 좋습니다. CPU모드가 바뀜에 따라 레지스터 자체가 별개
의 다른 것으로 바뀌었기 때문입니다.
해당 내용을 정리해 보도록 하겠습니다.
-----------------------------------------------------
User FIQ Super Abort IRQ Undefined
-----------------------------------------------------
r0 . . . . .
r1 . . . . .
r2 . . . . .
r3 . . . . .
r4 . . . . .
r5 . . . . .
r6 . . . . .
r7 . . . . .
r8 r8_fiq . . . .
r9 r9_fiq . . . .
r10 r10_fiq . . . .
r11 r11_fiq . . . .
r12 r12_fiq . . . .
r13 r13_fiq r13_svc r13_abt r13_irq r13_und
r14 r14_fiq r14_svc r14_abt r14_irq r14_und
r15(PC) . . . . .
-----------------------------------------------------
위의 그림이 각 모드에 따라 리맵핑 되는 레지스터들을 나타낸 그림입
니다. FIQ모드에서는 7개, 그리고 나머지 모드에서는 2개씩의 레지스터
가 리맵핑됩니다.
이 개념이 이해하기가 좀 어려울런지도 모르겠군요. 시간을 가지고 차
근 차근 생각해 보시길 바랍니다.
그러면 왜 다른 모드들에서는 r13과 r14를 따로 두었을까요? 그것은 그
레지스터들이 특별한 목적을 위해 사용되는 레지스터 이기 때문입니다.
레지스터차원에서 이번에는 IRQ가 발생한 경우를 가지고 설명해 보겠습
니다.
r14는 Link 레지스터로써 Call과 같은 인스트럭션이 발생할 경우 복귀
할 번지를 저장해 두는 레지스터 입니다. 다음은 IRQ 발생 과정입니다.
1) User모드에서 r0-r15를 사용하고 있다.
2) IRQ 발생
3) ARM CPU는 동작모드를 IRQ 모드로 바꾼다.
( 이때 r13과 r14는 IRQ 전용 레지스터로 대치된다.)
4) 이 시점의 PC 값은 IRQ 처리 이후 복귀할 번지이다. 그 값을
r14 (이미 IRQ모드가 되었으므로 r14_irq ) 에 넣는다.
5) 만약에 r0부터 r12까지를 IRQ처리 루틴에서 사용하고자 한다면
해당 레지스터를 sp(r13, 역시 r13_irq)를 사용하여 스택에 넣
는다.
.....
여기서 5)번 과정을 눈여겨 볼 필요가 있을 듯 합니다. r13이 스택 포인
터로 사용됨은 지난 강좌에서 말씀드렸었습니다. 그런데, 각 모드마다
r13을 따로 가지고 있으므로, 스택을 CPU 동작모드마다 따로 관리할 수
있게 되는 것입니다.
그림이라도 그려서 설명을 드리면 좋을 듯 한데, 텍스트로만 설명하기가
쉬운일이 아니군요.
r14는 복귀번지가 들어가기 때문에 항상 디폴트로 사용되므로 여분의 레
지스터가 필요하겠죠. 그런 이유로 r13과 r14를 각 모드마다 따로 둔 것
입니다. 혹시 이해가 되시나요?
FIQ모드는 그 이름에서도 나타나 있듯이 7개의 레지스터를 따로 두어서
레지스터 저장 복구 과정을 거의 생략할 수 있도록 한 것이죠.
그리고 참고로 Exception에서 복귀할 경우엔 기본적으로는 해당 모드의
r14 번지의 내용을 r15번지로 넣는데, 각 모드마다 조금씩의 차이가 있
습니다.
맨 처음 ARM7 을 소개할 때 범용 레지스터가 31개라고 말씀드렸었는데,
지금 다시 계산을 해보면, User모드의 디폴트 16개 + FIQ 모드 7개 +
나머지 4개의 모드 *2 =8개 해서 16+7+2+2+2+2=31 개로 계산이 됩니다.
- 동작 모드와 PSR(스테이터스 레지스터)
범용레지스터와 비슷하게 PSR 역시 동작모드마다 따로 관리가 됩니다.
해당 레지스터는 뒤에 모드 이름을 붙여서 SPSR_fiq, SPSR_svc,
SPSR_abt, SPSR_irq, SPSR_und 와 같은 이름으로 부릅니다. 따라서 PSR
개수는 CPSR을 포함하여 총 6개가 됩니다.
SPSR은 CPSR값을 저장해 두는 역할을 합니다. 범용레지스터가 아예 맵핑
이 바뀌는데 반해, 모드가 바뀔 경우, 예를 들어 IRQ가 발생했다면, 기
존에 User모드에서 사용하는 CPSR값을 SPSR_irq에 저장을 합니다. 그리
고 IRQ 모드에서는 CPSR과 SPSR_irq를 둘다 볼 수 있습니다. 후에 IRQ가
끝나는 시점에서 SPSR_irq의 내용을 CPSR로 복구하면 원래의 CPSR값이
유지되는 것이죠.
가만히 생각해보면 Exception이 발생했을 때 해당 처리 루틴에는 그순간
의 CPSR값을 그대로 가져오는 셈이지요. 다만 시작할 때 해당 값을 SPSR
에 저장해 두었기 때문에 IRQ 처리루틴에서 수정이 된다고 해도, 복귀할
때 SPSR에서 CPSR값을 다시 가져오므로, 실행중이던 환경은 그대로 유지
가 되는 것입니다.
이렇듯 ARM7에서는 Exception처리에 있어 되도록이면 스택 사용을 최소
화하려는 노력을 엿볼 수 있습니다.
오늘 강좌 내용은 좀 어려웠던것 같습니다. 다른 CPU에는 없는 개념(?)을
설명하느라 그랬던것 같습니다.
더이상 길어지기 전에 오늘은 이만 줄이려 합니다.
다음강좌에서는 Exception부분에서 좀 더 알아야 할 몇가지 사항을 간단히
언급하도록 하겠습니다.
----------------------------------------------------------------------
ARM7 강좌 [5] : Exception(1)
----------------------------------------------------------------------
* Exception
우선 Exception이 무엇을 말하는지부터 정리해 보고자 합니다. 일반적으
는 인터럽트와 유사한 개념으로 사용합니다. 어떻게 보면 인터럽트 보다
는 조금 큰 개념이랄 수도 있고, 정확한 정의에 대해서는 말씀을 드리지
못하겠군요. 개념을 ARM7에서의 Exception으로 한정해서 말씀드리겠습니
다.
구체적으로 ARM7에는 FIQ(Fast Interrupt reQuest)와 IRQ(Interrupt reQu-
est), Abort, Software Interrupt, Undefined Instruction Trap 의 5가지
Exception이 있고, 각각 Exception이 발생하면 CPU는 대응하는 동작모드
로 전환됩니다. 여기에 보통 동작상태인 User 동작모드가 추가되어 동작
모드는 총 6개가 있습니다.
- IRQ
: 일반적으로 I/O 장치로부터의 입력이 들어오면 반응을 하는 흔히 말
하는 인터럽트 Exception입니다. IRQ의 종류로는 내부 타이머나 시리
얼, 혹은 외부 IRQ입력 등이 될 수 있습니다.
- FIQ
: 개념적으로는 IRQ와 거의 유사한데, 다만 보다 빠른 처리를 할 수 있
도록 제공되는 Exception입니다. IRQ의 소스는 대부분 FIQ로도 맴핑
될 수 있습니다. 즉, 타이머 인터럽트를 IRQ로 처리하거나, 혹은
FIQ로 처리할 수도 있다는 의미입니다.
- Abort
: CPU가 메모리로부터 인스트럭션을 가져오거나, 혹은 인스트럭션을 동
작시키면서 데이터를 가져오려고 할 경우, 해당 메모리를 억세스 할
수 없다면 AbortException이 발생합니다. 위에 제시한 두가지 경우
에 대응하여 Prefetch Abort와 Data Abort로 구분할 수 있습니다.
- Software Interrupt
: 프로그램에서 임의로 인터럽트를 호출하는 경우입니다. ARM 인스트럭
션 SWI 가 이에 해당합니다. 이 Exception이 발생하면 CPU동작모드가
Supervisor 모드로 바뀌도록 되어 있고, 보통 OS의 시스템 Call을 구
현하기 위해 사용됩니다.
- Undefined Instruction Trap
: ARM7 에 정의되어 있지 않은 명령어를 만났을 경우 발생하는 Except-
ion입니다. 이 기능은 코프로세서를 사용하는 경우와 관련되어 사용
된다고 합니다.
위에서 언급한 5종류의 Exception에 몇가지를 더하여, 해당 처리를 위해
ARM7은 0번지에 벡터 테이블을 유지합니다. 즉, 해당 Exception이 발생하
면 정해져 있는 벡터 번지로 실행을 옮깁니다. 해당 번지는 다음과 같습
니다.
Address Exception Mode on entry
-----------------------------------------------------
0x0000.0000 Reset Supervisor
0x0000.0004 Undefined Instruction Undefined
0x0000.0008 Software Interrupt Supervisor
0x0000.000C Abort(prefetch) Abort
0x0000.0010 Abort(data) Abort
0x0000.0014 --reserved-- --
0x0000.0018 IRQ IRQ
0x0000.001C FIQ FIQ
한가지 주의할 점은 8086의 경우엔 해당 벡터에 ADDRESS를 넣어 두면, 인
터럽트 발생시에 해당 주소를 가져다가 PC에 넣어주는 일이 발생하지만,
ARM7의 경우엔 그냥 해당 벡터로 점프를 합니다. 예를 들어 IRQ가 발생했
다면 다음순간의 pc(r15)값은 0000.0018 이 됩니다. 따라서 해당 벡터 번
지에는 단순히 번지가 들어가는것이 아니라 점프명령 같은것이 들어갑니
다.
* 동작모드
위의 Exception과 관련되어 CPU의 동작모드 몇 가지가 나타나 있습니다.
전에도 몇번 말했듯이 ARM7에는 6가지의 동작 모드가 있습니다. 해당 모
드는 User Mode, FIQ Mode, IRQ Mode, Supervisor Mode, Abort Mode,
Undefined Mode 등의 6가지 입니다.
- 동작모드와 범용 레지스터
동작모드가 왜 있는걸까요? ARM7은 각 동작모드에 따라서 몇가지 기능
을 제공합니다. 가장 큰 것으로 레지스터를 리맵핑시키는 기능이 있습
니다. 좀 다르게 설명하면, 각 모드마다 전용 레지스터가 따로 있다고
도 표현할 수 있겠는데요, 차근차근 설명해 보도록 하겠습니다.
CPU의 동작모드는 보통때는 User 모드 입니다. 이 때는 기본적으로 r0
에서 r15 까지를 사용하고 있겠죠. 그러다 가령 FIQ가 발생했다고 치면
동작 모드가 FIQ 모드로 바뀌게 됩니다. 이와 동시에 r8 부터 r14 까지
의 7개의 레지스터는 FIQ 전용 레지스터로 리맵핑 됩니다. 즉, User모
드의 레지스터와는 별개였던 레지스터 7개가 r8부터 r14까지의 위치에
배치되는 것이죠. 물론 기존의 User모드에서 사용하던 r8-r14까지의 레
지스터와는 별개의 레지스터 입니다.
이렇게 하는 장점을 생각해 보겠습니다. 흔히 인터럽트 처리루틴을 작
성할 경우 인터럽트 발생시 가장먼저 하는일이 사용중이던 레지스터를
스택에 저장하고, 또 처리루틴이 종료될 때는 다시 복구시키는 일이었
습니다. 그러나 ARM7에서 FIQ의 경우를 살피면, FIQ 처리 루틴의 코딩
시에는 r8부터 r14까지를 자유롭게 사용할 수 있고, 또 저장과 복구과
정을 생략해도 좋습니다. CPU모드가 바뀜에 따라 레지스터 자체가 별개
의 다른 것으로 바뀌었기 때문입니다.
해당 내용을 정리해 보도록 하겠습니다.
-----------------------------------------------------
User FIQ Super Abort IRQ Undefined
-----------------------------------------------------
r0 . . . . .
r1 . . . . .
r2 . . . . .
r3 . . . . .
r4 . . . . .
r5 . . . . .
r6 . . . . .
r7 . . . . .
r8 r8_fiq . . . .
r9 r9_fiq . . . .
r10 r10_fiq . . . .
r11 r11_fiq . . . .
r12 r12_fiq . . . .
r13 r13_fiq r13_svc r13_abt r13_irq r13_und
r14 r14_fiq r14_svc r14_abt r14_irq r14_und
r15(PC) . . . . .
-----------------------------------------------------
위의 그림이 각 모드에 따라 리맵핑 되는 레지스터들을 나타낸 그림입
니다. FIQ모드에서는 7개, 그리고 나머지 모드에서는 2개씩의 레지스터
가 리맵핑됩니다.
이 개념이 이해하기가 좀 어려울런지도 모르겠군요. 시간을 가지고 차
근 차근 생각해 보시길 바랍니다.
그러면 왜 다른 모드들에서는 r13과 r14를 따로 두었을까요? 그것은 그
레지스터들이 특별한 목적을 위해 사용되는 레지스터 이기 때문입니다.
레지스터차원에서 이번에는 IRQ가 발생한 경우를 가지고 설명해 보겠습
니다.
r14는 Link 레지스터로써 Call과 같은 인스트럭션이 발생할 경우 복귀
할 번지를 저장해 두는 레지스터 입니다. 다음은 IRQ 발생 과정입니다.
1) User모드에서 r0-r15를 사용하고 있다.
2) IRQ 발생
3) ARM CPU는 동작모드를 IRQ 모드로 바꾼다.
( 이때 r13과 r14는 IRQ 전용 레지스터로 대치된다.)
4) 이 시점의 PC 값은 IRQ 처리 이후 복귀할 번지이다. 그 값을
r14 (이미 IRQ모드가 되었으므로 r14_irq ) 에 넣는다.
5) 만약에 r0부터 r12까지를 IRQ처리 루틴에서 사용하고자 한다면
해당 레지스터를 sp(r13, 역시 r13_irq)를 사용하여 스택에 넣
는다.
.....
여기서 5)번 과정을 눈여겨 볼 필요가 있을 듯 합니다. r13이 스택 포인
터로 사용됨은 지난 강좌에서 말씀드렸었습니다. 그런데, 각 모드마다
r13을 따로 가지고 있으므로, 스택을 CPU 동작모드마다 따로 관리할 수
있게 되는 것입니다.
그림이라도 그려서 설명을 드리면 좋을 듯 한데, 텍스트로만 설명하기가
쉬운일이 아니군요.
r14는 복귀번지가 들어가기 때문에 항상 디폴트로 사용되므로 여분의 레
지스터가 필요하겠죠. 그런 이유로 r13과 r14를 각 모드마다 따로 둔 것
입니다. 혹시 이해가 되시나요?
FIQ모드는 그 이름에서도 나타나 있듯이 7개의 레지스터를 따로 두어서
레지스터 저장 복구 과정을 거의 생략할 수 있도록 한 것이죠.
그리고 참고로 Exception에서 복귀할 경우엔 기본적으로는 해당 모드의
r14 번지의 내용을 r15번지로 넣는데, 각 모드마다 조금씩의 차이가 있
습니다.
맨 처음 ARM7 을 소개할 때 범용 레지스터가 31개라고 말씀드렸었는데,
지금 다시 계산을 해보면, User모드의 디폴트 16개 + FIQ 모드 7개 +
나머지 4개의 모드 *2 =8개 해서 16+7+2+2+2+2=31 개로 계산이 됩니다.
- 동작 모드와 PSR(스테이터스 레지스터)
범용레지스터와 비슷하게 PSR 역시 동작모드마다 따로 관리가 됩니다.
해당 레지스터는 뒤에 모드 이름을 붙여서 SPSR_fiq, SPSR_svc,
SPSR_abt, SPSR_irq, SPSR_und 와 같은 이름으로 부릅니다. 따라서 PSR
개수는 CPSR을 포함하여 총 6개가 됩니다.
SPSR은 CPSR값을 저장해 두는 역할을 합니다. 범용레지스터가 아예 맵핑
이 바뀌는데 반해, 모드가 바뀔 경우, 예를 들어 IRQ가 발생했다면, 기
존에 User모드에서 사용하는 CPSR값을 SPSR_irq에 저장을 합니다. 그리
고 IRQ 모드에서는 CPSR과 SPSR_irq를 둘다 볼 수 있습니다. 후에 IRQ가
끝나는 시점에서 SPSR_irq의 내용을 CPSR로 복구하면 원래의 CPSR값이
유지되는 것이죠.
가만히 생각해보면 Exception이 발생했을 때 해당 처리 루틴에는 그순간
의 CPSR값을 그대로 가져오는 셈이지요. 다만 시작할 때 해당 값을 SPSR
에 저장해 두었기 때문에 IRQ 처리루틴에서 수정이 된다고 해도, 복귀할
때 SPSR에서 CPSR값을 다시 가져오므로, 실행중이던 환경은 그대로 유지
가 되는 것입니다.
이렇듯 ARM7에서는 Exception처리에 있어 되도록이면 스택 사용을 최소
화하려는 노력을 엿볼 수 있습니다.
오늘 강좌 내용은 좀 어려웠던것 같습니다. 다른 CPU에는 없는 개념(?)을
설명하느라 그랬던것 같습니다.
더이상 길어지기 전에 오늘은 이만 줄이려 합니다.
다음강좌에서는 Exception부분에서 좀 더 알아야 할 몇가지 사항을 간단히
언급하도록 하겠습니다.