본문 바로가기

Hacked Brain/embeddedland.net

ARM7 강좌 [5] : Exception(1) (출처 : 디지털 동호회)

출처 : 디지털 동호회
----------------------------------------------------------------------
                     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부분에서 좀 더 알아야 할 몇가지 사항을 간단히
언급하도록 하겠습니다.