본문 바로가기

Hacked Brain/embeddedland.net

ARM7 강좌 [13] : Instruction Set(7) (출처 : 디지털 동호회)

2007/10/19 - [임베디드/ARM] - ARM7 강좌 [12] : Instruction Set(6) (출처 : 디지털 동호회)
----------------------------------------------------------------------
               ARM7 강좌 [13] : Instruction Set(7)
----------------------------------------------------------------------

* Block Data Transfer 명령(LDM,STM)

  해당 명령은 개인적인 생각으로 참 독특하다고 생각합니다. 지난  강좌에
  서 다루었던 LDR, STR과 마찬가지로 실제 메모리에 레지스터의 내용을 전
  달 하거나, 전달 받을 수 있는 명령입니다. ARM7에서는 이런  명령이  몇
  안되죠...

  LDR명령이 메모리 번지의내용을 지정된 레지스터로 가져오는 명령이라면
  LDM은 가져오긴 하는데, 여러개의 레지스터의 내용을 한큐에 가져오는 명
  령입니다. 가장 많이 사용되는 경우는 스택 연산인것 같습니다. 전에  말
  씀드렸었지만, ARM7에는 Push, Pop 명령이 없습니다. 대신 LDR이나 STR을
  쓸 수도 있겠고... 또 LDM이나 STM을 쓸 수도 있죠... 후자 쪽이 더 많이
  사용되는 듯 합니다.

  1) {cond}mode   Rn{!},{reg_list}{^}

    위 명령에서 {cond}는 늘 보아오던 명령어 실행 조건입니다. Rn은 전송
    에 사용될 베이스 번지를 지정하는 레지스터입니다. !를  붙이면  Wrte
    Back 기능이죠... LDR과 STR에서 다루었습니다. 자세한 내용은  뒤에서
    언급하도록 하겠습니다.

    {reg_list} 부분은 전송하거나 전송받을 레지스터의  목록을  나타내는
    부분입니다. 예를 들어 1000번지에 r1,r2,r3를 저장하고 싶다 했을  경
    우에, 일단 1000번지 값을 어떤 레지스터에 넣어두고...  여기서는  그
    레지스터를 r13이라고 하죠, 그러면 Rn은 r13이 되는 거구요,
    {reg_list}는 {r1,r2,r3} 이 되는 것입니다. mode 라고 되어있는  부분
    은 여러개의 레지스터를 메모리에 넣거나 가져올 때 어떤 방식으로  동
    작할지를 지정하는 접미사입니다. 이 접미사 종류가 8가지가 있는데요.

    무지하게 복잡해 보입니다. 일단은 각 요소의 의미만 간단하게  정리하
    고, 다음으로 넘어가죠.

    마지막으로 {^}부분은... 글세요 잘 이해가 안되는 부분입니다만...
    제가 보는 책과 데이터 시트에서 예제가 나와 있지 않군요. 그냥  문서
    의 내용을 그대로 적어보겠습니다.

    {^} if present set S bit to load the CPSR along with the PC, or
        force transfer of user bank when in privileged mode...(???)

    자... 그럼 이제 본격적으로 설명에 들어가겠습니다.

    먼저 1단계, LDM 과 STM의 의미 입니다.

       LDM : 베이스 레지스터(Rn)로 지정된 번지에서 레지스터 목록으로 지
             정된 각 레지스터의  내용을 읽어들이는 명령.

       STM : LDM과 반대.

    여기까지는 별 무리가 없으리라 생각합니다. 혹시 이  명령을  8086등에
    있는 블럭 데이타 전송명령 등과 혼동하지 않으시길 바랍니다. 어렴풋이
    기억하는데, 8086등에는 메모리에서 메모리로 블럭 전송을 할  수  있는
    명령이 있죠... 또는 특정 길이만큼 메모리를 어떤 값으로 설정하는  블
    럭 설정 명령도 있었던 듯 합니다.

    ARM7의 LDM과 STM은 블럭 전송이 아니라 Multiple Register 전송입니다.
    쉽게 생각하면

        push    ax
        push    bx
        push    cx
        push    dx

    가 8086형태라고 할 때, ARM7에서 Single 데이터 전송 명령을 사용하면

        STR     r0,[sp],#4
        STR     r1,[sp],#4
        STR     r3,[sp],#4
        STR     r4,[sp],#4

     쯤이 되겠고, 또 Multiple 전송명령을 사용하면,

        STMEA   sp!,{r0,r1,r2,r4}

     제가 방금 적어본 것이라 맞는 것인지 확신은 없습니다만... 그냥  개
     념이 이렇다는 것만 파악하셨으면 합니다.

     그러면 이제 2단계, {Reg_List}를 자세히 다루어 보죠... 위의 예에서
     나와있듯이 중괄호 사이에 전송 대상이 되는 레지스터를 넣어주면  됩
     니다. 그렇다면 몇개까지 가능한 것일까요? ARM7에서 한시점에 사용할
  수 있는 레지스터의 개수는 r0에서 r15까지 총 16개죠..
     LDM이나 STM명령에서 지정할 수 있는 레지스터의 개수는 최대 16개 입
     니다. 즉, 한 명령으로 모든 레지스터를 저장하거나, 가져올 수  있다
     는 의미입니다.

     참 재미있는 사실은, LDM명령의 니모닉상에 16비트의  공간이  있어서
     각 비트가 레지스터 r0-r15와 1:1로 대응이 된다는 사실입니다.  따라
     서 {reg_list}에는 어떠한 레지스터의 조합도 올 수 있습니다. 감동 !

     그리고 어셈블러의 문제겠지만, {r0,r2} 이런 형식뿐만 아니라,
     {r0-r5} 와 같은 형식, {r0-r3,r6-r7} 이런 형식도 사용할 수  있습니
     다.

     마지막으로 확인할 것은, {r3,r2,r1} 이렇게 썼을 때와 {r1,r2,r3} 이
     렇게 썼을 경우, 메모리에 저장되는 순서가 다를까요.. 아닐까요....
     말씀드렸듯이 16비트의 비트필드가 존재해서 각각 레지스터와 1:1대응
     이 된다고 하였으니... 소스코드에서 어떤 형식을 쓰든... 니모닉으로
     변환될 때는 그 순서는 아무 의미가 없겠지요.. 결국 같다는 말입니다.

     자... 이번에는 3단계입니다. 동작 모드!!!

     위의 STM명령에서 제가 STMEA라고 명령을 적었습니다. EA가  동작모드
     를 지정하는 부분입니다. 이와 같은 키워드가 8가지가 있고, 동작모드
     는 4가지가 있습니다.

     먼저 4가지의 동작모드를 말씀드리겠습니다.

     A) Post-Increment Addressing

        여기서 동작모드는 여러개의 레지스터값을 메모리로(혹은 로부터)
        전송할 경우 해당 메모리 번지를 증가시키면서 저장할지, 혹은  감
        소시키면서 저장할지를 지정하는 것과, 증/감을 하는데,  저장하기
    전에 증/감을 할지, 아니면 저장하고 나서 증/감을 할지를  지정하
        는 것을 의미합니다.

        처음 설명할 동작모드는 저장 이후 증가하는 방식입니다.

        예를 들어 R10에 0x1000이 들어있다고 가정하고 R10을  베이스레지
        스터로 사용해서 {r1,r2}를 저장한다면, Post-Increment모드에서는,

                1. 0x1000 번지에 r1이 저장된다.
                2. Base 번지값이 0x1004로 증가한다.
                3. 0x1004 번지에 r2가 저장된다.
                4. Base 번지값은 0x1008로 증가한다.

        만약 !를 사용했다면 r10의 값은 0x1008이 될 것입니다.

    B) Pre-Increment Addressing

        말 그대로 먼저 증가하고 다음에 저장하는 동작 모드입니다.
        위와 같은 조건을 가정해 봅시다.

                1. Base 번지값이 0x1004로 증가한다.
                2. 0x1004번지에 r1이 저장된다.
                3. Base 번지값이 0x1008로 증가한다.
                4. 0x1008번지에 r2가 저장된다.

        역시 !를 사용했다면 r10의 값은 0x1008이 됩니다.

    C) Post-Decrement Addressing

        이번에는 베이스 번지가 감소하는 경우죠. 좀 특이한 것은,  감소
        모드로 저장(로드)을 할 경우 아까는 레지스터번호가 빠른 것부터
        저장하거나 불러들였는데, 이번에는 거꾸로라는 것입니다. 결과적
        으로, 메모리에 저장되는 레지스터의 순서는 항상 동일하다는  것
        이죠... 마찬가지로 같은 조건에서 예제를 들겠습니다.

                1. 0x1000번지에 r2가 저장된다.(!!! r1이 아니라 r2)
                2. Base번지값이 0x0FFC로 감소된다.
                3. 0x0FFC번지에 r1이 저장된다.
                4. Base번지값이 0x0FF8로 감소된다.

        만약 !를 사용했다면 r10의 값은 0xFF8이 된다.

    D) Pre-Decrement Addressing

                1. Base번지값이 0x0FFC로 감소된다.
                2. 0x0FFC번지에 r2가 저장된다.
                3. Base번지값이 0x0FF8로 감소된다.
                4. 0x0FF8번지에 r1이 저장된다.

        만약 !를 사용했다면 r10의 값은 0xFF8이 된다.

    여기까지 4개의 동작모드를 설명했습니다.

    동작모드를 나타내는 키워드는 8개인데요... 각각의 동작모드에 대해서
    스택처럼 사용할 경우, 혹은 아닐 경우 2가지로 나누어서 나타내기  때
    문입니다.

    다음 표는 각 동작모드에 대한 명령어입니다.

    ==================================================================
           동작                         Stack           Other
    ------------------------------------------------------------------
        pre  increment load             LDMED           LDMIB
        post increment load             LDMFD           LDMIA
        pre  decrement load             LDMEA           LDMDB
        post decrement load             LDMFA           LDMDA

        pre  increment store            STMFA           STMIB
        post increment store            STMEA           STMIA
        pre  decrement store            STMFD           STMDB
        post decrement store            STMED           STMDA
    ==================================================================

    Stack인 경우와 아닌경우 키워드가 다른 것은, 단지 유저의 편이를위한
    배려라고 생각됩니다. 즉, 키워드를 LDMED로 썼을 경우나 LDMIB로 썼을
    경우, 동작상에 차이는 없는 듯 합니다.

    키워드를 무작정 붙인것 같지는 않구요... 먼저 Other의 키워드를 살피
    면, I는 increment를 의미하구요..  D는  decrement겠죠..  그리고 B는
    Before를, A는 After를 의미합니다.

    그러므로 만약 LDMDA 는 post decrement 모드를 의미하는 것이죠....

    Stack의 경우엔, E는 Empty를 F는 Full을 의미한답니다. 스택을 구현하
    는 경우 현재 sp가 가리키는 번지의 내용이 차있는지, 비어있는지를 의
    미한다고 보시면 될 듯 합니다. 무슨얘기냐면... 만약 Post 모드를  사
    용한다면, 스택을 구현할 경우, 어떤 내용을 넣고 다음에 번지를 증/감
    하므로 결국 어떤 시점에서 스택포인터가 가리키는 번지는 비어있게 됩
    니다. 이 경우 Empty가 되겠죠...

    Load의 경우엔 Empty 형태의 스택이라면 sp가 가리키는 공간에 아무 내
    용도 없으므로 먼저 sp를 변화시키고 데이터를가져와야겠죠..  그래서
    Load는 Pre가 Empty 와 대응이 됩니다. 하지만 반대로 Store의  경우엔
    Empty 형태의 스택을 위해서는 먼저 데이터를 넣고 sp를 변화시켜야 합
    니다. 그렇다면 post모드가 Empty와 대응이 되겠군요..!!

    Full은 더이상 말 안해도 되리라 믿습니다.

    다음으로 D는 Decending, A는 Ascending을 의미합니다. 이것은  스택이
    거꾸로 커지는지 아니면 반대인지와 관련이 있습니다. 8086에서는 Push
    를 하면 sp값이 작아지죠? 그렇다면 decending Stack이라고 볼 수 있습
   니다. push와 STM이 대응되므로 STM의 Decrement 모드는 D 라는 키워드
    를 사용했군요... Pop의 경우는 LDM과 대응되고  decending  stack에서
    Pop을 할경우 sp값은 증가되어야 겠죠... 그래서 LDM에서는  increment
    모드가 D입니다.

    A는 반대이겠죠... 결국 스택관련 명령에서는 LDM이나 STM에서 같은 접
    미사를 사용하면 되는 것입니다. 물론 동작 방식은 LDM과 STM에서 각기
    다르지만요...

자.. 이제 예제를 하나 보이고 오늘 강좌를 정리하려 합니다.


     STMED      sp!,{r0-r3,r14}

     BL         somewhere

     LDMED      sp!,{r0-r3,r15}

     첫번째 명령에 STMED는 Empty Decending Stack Operation이므로  실제
     로는 post-decrement 동작모드를 의미하죠.. sp(r13)가 가리키는 번지
     에 r0,r1,r3,r14를 저장합니다. BL로 이 루틴에 들어왔다면 r14에  복
     귀 번지가 들어가 있다는것을 감안하십시요..

     BL에서 뭔가 처리를 하고, 마지막으로 LDMED명령에서 레지스터를 복구
     합니다. 이번에는 pre-Increment 동작모드입니다.

     한가지 주의하실 점은 r14대신에 r15로 복구를 시켰다는 것입니다.
     ARM7에서는 ret명령 대신 mov r15,r14 를 사용한다고 말씀드렸었죠...

     LDMED 명령에서 레지스터 복구와 서브루틴 복귀를 동시에 처리하는 부
     분입니다.


자... 오늘 강좌는 이렇게 정리할까 합니다. 거의 1달만에 강좌를 썼군요.
그동안 메일이나 게시판을 통해서 질문과 격려를 보내주신 분들에게...  죄
송하다는 말씀을 드려야 겠군요...

차일피일 미루다보니..쩝.

이제 강좌도 종반을 향해 달리고 있습니다. 아마도 2회 정도면 계획했던 모
두가 끝이 날것 같군요... 다음 강좌를 기약하며 이만 줄이겠습니다.

2007/10/19 - [임베디드/ARM] - ARM7 강좌 [12] : Instruction Set(6) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [11] : Instruction Set(5) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [10] : Instruction Set(4) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [9] : Instruction Set(3) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [8] : Instruction Set(2) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [7] : Instruction Set(1) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [6] : Exception(2) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [5] : Exception(1) (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [4] : 레지스터 (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 [3] : ARM7의 구조 (출처 : 디지털 동호회)
2007/10/19 - [임베디드/ARM] - ARM7 강좌 2 개요 (출처 : 디지털 동호회)