ARM7 강좌 [10] : Instruction Set(4)

 


  오늘 강좌에서는 Data Processing Instruction에 대해서 계속 이어나가도록 하겠습니다. 되도록이면 오늘 이 부분을 다 커버하고 싶습니다만 해봐야겠지요. 지난 강좌에서 다루었던 내용 중 오퍼랜드쪽 부분은 계속 겹치는 내용이므로 의문이 생기시면 이전 강좌로 돌아가서 확인해 보시길 바랍니다.


1) MVN{cond}{S}       Rd,Op2

   

   해당 명령은 Rd:=NOT Operand2 의 의미를 가진 명령입니다. 기존 어셈블러에서는 볼 수 없었던 낯선 명령이네요. 기능은 써 있듯이 MOV처럼 값을 넣기는 넣는데 NOT를 해서 넣는 명령입니다. 이런 명령이 왜 있는지에 대해서는 확실히 모르긴 몰라도, 아마도 ARM7에서 8비트Resolution Immediate 오퍼랜드만 다룰 수 있기 때문인 듯 합니다. 해당 명령으로 어느 정도 기능을 확장한다고 할까요?


   바로 예제로 들어가겠습니다.


   Ex1) MVN   r0,#0          ; r0 := -1

        : 사실 MVN의 용도로 위의 경우 밖에는 사용된걸 보지 못했습니다. 만약 MOV  r0,#0xFFFFFFFF 이렇게 하면 에러가 발생합니다. 이것은 매번 설명 드리지만 ARM7의 모든 명령이 32비트 한 워드이고 Immediate 오퍼랜드처리를 8비트 값을 Rotate시키는 방식으로 사용하기 때문인데, MVN을 사용함으로서 해당 값을 넣을 수 있습니다.


   다른 부분은 MOV와 동일하므로 그다지 이슈가 될 것이 없을 듯 하군요.


2) ADD{cond}{S} Rd, Rn, Op2

   ADC{cond}{S} Rd, Rn, Op2


   더하기 명령입니다. 8086과 큰 차이는 오퍼랜드를 3개 지정한다는 것입니다. Rd는 결과가 저장될 레지스터로, Data Processing 명령 모두는 그 결과가 레지스터(Rd)로 들어가야만 합니다. 첫 번째 Rd가 결과가 저장 될 레지스터이고, 나머지 두개가 서로 더해질 오퍼랜드입니다. 두개의 오퍼랜드 중 하나는 또 항상 레지스터여야만 합니다. Op2는 거듭 말씀드리지만 Shifted Register 혹은 Rotated Immediate Value 중 하나입니다.


   ADD와 ADC는 널리 사용되는 대로 더하기, 더하는데 캐리플래그랑 같이 더하기 정도입니다.


   Ex1) ADD   r0,r0,#1 ; r0:=r0+1


   Ex2) ADD   r0,r1,r2 ; r0:=r1+r2


   Ex3) ADDS  r0,r1,r1, LSL #2 ; r0:=r1*5

        : 위의 명령을 보면 ARM 명령어의 강력함을 알 수 있죠?  위에서 Rd는 r0, Rn은 r1, Op2 부분이 r1,LSL #2 입니다. r1값 더하기 r1을 두 번 쉬프트 한 값, 즉 r1*4값이므로 결과적으로는 *5가 되겠지요. S 옵션이 사용되었으므로 플래그 레지스터에 영향을 미칩니다. 그러면? 위의 1번 2번 예제는 수행하더라도 플래그 레지스터는 영향을 안받는다는 의미지요. 사용하기에 따라서 강력한 역할을 할 수 있을 듯 합니다.


   Ex4) in C

        

        int addints(int a,int b)

        {

            int c;

            c=a+b;

            return c;

        }


        in ARM7 Assembly


        ADD       r0,r0,r1     ; r0:=r0+r1

        MOV       pc,lr       ; return


        사실 인수 전달에 관련된 코드가 더 들어가지만, 코어부분은 대강 위와 같습니다.


3) SUB{cond}{S}       Rd, Rn, Op2

   SBC{cond}{S}      Rd, Rn, Op2

   RSB{cond}{S}       Rd, Rn, Op2

   RSC{cond}{S}      Rd, Rn, Op2


   위의 네 명령은 빼기 명령입니다. SUB와 SBC는 그런데로 알만 한데, R로 시작하는 두개가 더 있네요. R은 감수(?) 와 피감수를 바꾸는 역할을 합니다. 즉, SUB 명령이 Rd=Rn-Op2 라면 RSC는 Rd=Op2-Rn 입니다. 이런 명령이 왜 필요할 까요? 글쎄요. 우선 Op2가 Rn에 비해서 상대적으로 유연성이 좀더 많아서일까요? 어떻든... 개념은 어렵지 않습니다.


   SBC와 RSC는 캐리플래그가 관련되어 있는 명령입니다. 그런데 명령 해석을 보면 다음과 같이 나와 있네요.


      SBC Rd, Rn, Op2 = Rd=Rn-Op2+Carry-1


   아마도 8086에서의 Carry와는 좀 다른 모양입니다. 뺄셈을 했을 때 자리 내림이 발생을 하면 Carry가 클리어 되는 구조이군요. 아마도 2의 보수 연산을 하기 때문인 듯 합니다. 즉 1을 빼고 싶은 경우 1의 2의 보수를 취해 더해주죠. 해당 값은 FFFFFFFF 이고, 대상이 0이 아니라면 더하기를 통해 Carry가 발생하겠군요. 근데 원래 하고자 했던 것이  뺄셈이었으니까... 피감수가 0인 경우에 Carry가 발생하지 않았고, 나머지의 경우에는 모두 Carry가 발생합니다. 기계적 사고방식에는 그게 맞나 봅니다.


   어떻든 중요한 것은 뺄셈 연산을 통해 borrow가 발생한다면 Carry는 0이고 발생하지 않는다면 Carry는 1이 되는 것이죠. 따라서 SBC와 같은 명령에서는 Carry를 오히려 더해주고 다시 1을 빼 줌으로써 8086 등에서 사용되는 것과 동일한 효과를 얻게 되는군요.


   Ex) 64Bit 뺄셈


       SUBS   r4,r0,r2

       SBC    r5,r1,r3


       : 이렇게 하면 [r5:r4]=[r1:r0]-[r3:r2]가 되겠군요. {S}옵션에 주의하시길 바랍니다.


4) AND{cond}{S} Rd, Rn, Op2

   EOR{cond}{S} Rd, Rn, Op2

   ORR{cond}{S} Rd, Rn, Op2


   : 이번에는 Bit연산에 관련된 명령어들입니다. AND는 그대로 AND, EOR은 XOR쯤으로, ORR은 OR로 생각하시면 됩니다. B명령을 제외하고는 웬만한 명령어는 모두 3글자인데, 그래서 ORR로 표기하는 듯합니다. 역시 오퍼랜드는 같은 의미입니다.


   Ex1) AND   r0,r0,#0xFF

       : r0의 8비트만 남기는 명령입니다.


   Ex2) ANDCSS       r0,r1,r2,ASR r3

       : 만약 캐리 플래그가 설정되어 있다면...(CS) r1 AND (r2>>r3) 정도를 하는데, 해당 명령의 결과가 플래그 레지스터에 영향을 미칩니다. ASR과 LSR의 차이는 ASR의 경우 최상위 비트가 1이라면 해당 비트는 계속 1로 유지를 하는 것이죠. LSR이라면 새로 들어오는 비트는 항상 0입니다. 이것은 음수를 2의 보수로 사용하는 시스템에서 필요한 방법입니다. 참 결과는 r0에 넣는군요.


   Ex3) EORS  r0,r0,r0

       : 해당 명령을 수행하면 r0는 0이 될 것이고, N 플래그도 0이 되고 Z플래그는 1이 됩니다.


   Ex4) MOV   r0,#0xFF

        ORR   r0,r0,#0xFF00

       : r0에 0xFFFF를 넣는 방법입니다.


5) BIC{cond}{S}       Rd, Rn, Op2

   

   : Rd := Rn AND (NOT Op2) 로 설명이 되어 있는 명령입니다. 별별 명령이 다 있다는 생각이 드는군요. AND하기 전에 NOT을 한번 해서 처리하는 명령입니다. 의미는 비트를 클리어 하는 것이고, Op2에 지정한 비트가 0으로 지워지는 결과가 나타납니다.


   Ex) BIC     r0,r1,#3

       : r0 := r1 and 0xFFFFFFFC 의 의미입니다.


6) CMP{cond} Rn, Op2

   CMN{cond} Rn, Op2


   : 비교 명령입니다. MOV, MVN처럼 인수가 2개인데요, 이번에는 Rd가 빠졌습니다. CMP는 흔히 보던 그 CMP입니다. Rn에서 Op2를 빼 보는 명령이죠. 아시다시피 레지스터 값에는 영향을 미치지 않고 플래그에만 영향을 미칩니다. 그러고 보니 {S}옵션도 없네요. 이 명령들은 디폴트로 {S}를 준 효과가 나타납니다. (일설에는 어셈블러가 그렇게 해 준다고 하던데, 기계어 코드로는 S옵션을 꺼놓은 CMP도 가능하지 않을까 싶네요.)


     CMN은 좀 새롭군요. 이 명령은 CMP가 빼기를 하는데 반해, 두 오퍼랜드를 더해 보는 명령입니다. 역시 생소한 개념인데요. 그럴 필요도 있을까요? 어떻든 CMP가 빼기를 해보는 거라면 CMN은 더하기를 해 보는 명령어랍니다.


   Ex1) CMP   r2,#23

        MOVEQ r2,#45

       : 만약 r2가 23이라면 45를 넣어라.


   Ex2) CMP   r0,#0

        CMPEQ r1,#0

        CMPEQ r2,#0

        CMPEQ r3,#0


        MOVEQ r4,#12


        : r0부터 r3까지 모두 0이라면 r4에 12를 넣는 명령입니다. 참 재미있는 구조라고 생각됩니다.


   Ex3) CMN   r1,r2

        MOVEQ r0,#0

        MVNNE r0,#1


        : r0 = ((r1+r2)==0) ? 0:-1;


   위에서 조건부 명령의 강력함을 느낄 수 있나요? 아니라면 다음을 한번 보시죠.


   in C

        while (a!=b) {

            if (a>b) a-=b;

            else     b-=a;

        }


   in ASM with no conditional Instruction


        gcd    CMP   a,b

                JZ     end

                JNZ    less_than


                SUB   a,a,b

                JMP    gcd


        less_than

                

                SUB   b,b,a

                JMP    gcd

        

        end    

                ...


        ※ ARM도 아니고 8086도 아니고, 명령어가 이상하게 되었네요. 대충 의미만 파악하시길.


   in ARM7


        gcd    CMP   a,b

                SUBGT a,a,b

                SUBLT b,b,a

                BNE    gcd


        직접 보시고, 소감을.


7) TEQ{cond} Rn, Op2

   TST{cond} Rn, Op2


   : CMP와 거의 비슷한 구조를 갖는 명령입니다. 기능도 거의 유사합니다. CMP가 -, CMN이 + 라면, TEQ는 XOR, TST는 AND 연산을 통해 같은 일을 합니다. 하지만 특징이라면 Logical 연산이 일어날 경우 플래그 중에서 V 플래그(오버플로우 플래그)는 영향을 받지 않습니다. 이걸 잘 응용하면 다음과 같은 처리가 가능합니다.



  Ex1) CMP   r0,#31         ; test r0<=31 ?

        TEQ    r0,#127         ; test r0==127 ?

        MOVLS r0,#'.'          ; if either then r0='.'


  Ex2) TST    r1,#3          ; is r1 word aligned?

        MOVEQ r0,#1          ; r0:=1 if so

        MOVNE r0,#0          ; else r0:=0



  지난번에 다루었던 MOV 명령까지를 합치면 총 16개의 명령을 설명 드렸습니다. 이로서 가장 비중이 큰(분량이 많은?) Data Processing 명령의 설명을 마쳤군요.


참고로 다루고 있는, 혹은 앞으로 다룰 명령의 종류는 다음과 같습니다.


   (1) Branch 명령

   (2) Data Processing 명령

   (3) PSR Transfer 명령

   (4) Multiply 명령

   (5) Single Data Transfer 명령

   (6) Block Data Transfer 명령

   (7) Swap 명령

   (8) SWI 명령


  이밖에도 코프로세서 관련 명령이 있기는 하지만, 그 정도까지는 좀 무리인 듯 싶습니다.

위에 써 놓은 것을 보니 무척 많아 보이는데요, 막상 살펴보면 분류 당 1개~2개정도의 명령밖에는 없습니다.


  자, 그럼 오늘 강좌는 여기에서 줄이겠습니다.

+ Recent posts