Data Processing Instructions

Arithmetic Operations

 

앞에서는 논리적인 연산들 (Bolean / AND (&), OR (^) 등) 에 대해 알아보았다. 이번에는 논리 연산이 아닌 직접적인 수와 수 사이의 산술에 대한 연산 ( ADD (+), SUB (-)) 들에 대해 알아볼것이다.

 

시스템 프로그래밍 - 4 (1) : Data Processing Instructions - Logical operations

 

+ 모든 Data Processing Instructions 은 오직 레지스터에서만 실행된다. 절대로 메모리에서 실행되지 않는다.

 

 - Basic Arithmetic Operations

 

Add : 덧셈

-    ADD    r0, r1, r2        @ r0 := memory [r5]

 

Subtract : 뺄셈

-    SUB     r0, r1, #3       @ r0 := memory [r5]

 

Reverse Subtract : 역 뺄셈

-    RSB     r0, r1, r2        @ r0 := memory [r5]

 

  왜? Subtract 가 있는데 Reverse-Subtract 라는 것을 따로 만들었을까?

이유는, 모든 Instruction 들은 기본적인 사용 형식이 있다. ( 4 (1)에서 설명 ) XXX rd, rm, op 와 같이 각각 rd, rm, op 에 들어갈 수 있는 것들이 따로 정의되어 있는데 rm 의 부분에는 #3과 같은 상수값이 들어갈 수가 없다 (오직 레지스터만 들어갈 수 있다.). 그래서 SUB r0, r1, #3 대신 SUB r0, #3, r1 이렇게 자리를 바꾸어서 [ 상수(#7) - 레지스터안의 값(r1) ] 형태로 SUB을 쓸 수 없기에 RSB를 사용하는 것이다. 

 

 

 

 - Condition Code Flags

 

Condition 은 굉장히 중요한 부분이면서, ARM 프로그래밍에 있어서 여러 코드들을 프로그래머 마음대로 이용할 수 있게 만들어 주는 유용한 코드이다. Condition 코드는 다른 Instruction set 들과 똑같이 32 bits 레지스터를 할당받는데, Conditon 코드 전체 32 bits 의 각 비트는 산술 및 논리 연산의 결과를 저장하여 조건 분기 명령의 조건을 표시한다. 조건 분기 명령의 조건을 표시한다는 점에서, 조건 분기가 많이 쓰이는 프로그래밍 분야에서 이것이 얼마나 중요하고, 유용한 코드인지 알 수 있다. 

 

사용자 수준(User Mode)의 프로그램에서는 일반적으로 레지스터가 어떻게 구성되어 있는지 자세히 알 필요는 없다. Condition 코드(PSR = CPSR)는 전체 32 bits의 '방'을 제공받으며, 상태 레지스터(PSR)라고도 불리우며, 32bits 의 '방'은 Flag bits 와 Control bits 로 나누어져있다. PSR(=CPSR) 에서 우리가 공부할 파트인 '사용자 수준(User Mode)의 프로그램'에서 알아야할 것은 Flag bits 뿐이다.

 

 

 

 - CPSR ( Corrent Program Status Register )

 

CPSR 은 PSR 이라는 상태 레지스터 (Statue register) 이며 월래 본 명칭은 PSR 이지만, CPSR 로도 부른다. PSR 에는 위에서도 말했듯이 Flag bits 부분과 Control bits 부분으로 나누어지지만 여기에서는 우리에게 필요한 Condition Code Flags 만을 알아보자.

 

CPSR 의 전체 32bits 의 '방'에서 최상위 부분(MSB)에 있는 4 bits 가 Flags bits 이다. ( CPSR의 상위 MSB '4 비트' = N, Z, C, V ) Flag는 말 그대로 깃발이라는 뜻으로, 어떠한 정보를 청기(1) 혹은 백기(0)를 들어서 특정 성질의 유무를 쉽게 알아볼 수 있게 만든것이다. 다음 Flag 들은 특정 정보가 맞으면 '1' 이라는 값을 갖고, 틀리면 '0'이라는 값을 가진다.

 

N : Negative result - 바로 이전의 Computation 에서 결과 값이 음수인가 아닌가?

Z : Zero result - 바로 이전의 Computaion 에서 결과 값이 제로(영)인가 아닌가?

C : Carried out - 바로 이전의 Computaion 에서 Carry out 이 발생하였는가?

V : oVerflowed - 바로 이전의 Computaion 에서 oVerflow 가 발생하였는가?

 

어떤 특정한 Computation 의 결과로 발생하는 N, Z, C, V 에 대한 Flag 값들을 읽어내기 위해 그 특정 Computation 을 실행하는 Instruction 에 접미어 S 를 붙이면 그 Computation 이후에 여러 조건들(N, Z, C, V)에 해당하는 Condition flag 에 값들을 1과 0으로 세팅하게 된다. (Postfix "S") 그리고 우리는 그 세팅된 flag 값들을 이용하기만 하면 된다.

 

ex. ADD    r2, r2, r0 / ADDS    r2, r2, r0 - S 가 붙은 후자의 Instruction 에서만 Flag 값들이 설정된다.

 

 

 

 

 - Arithmetic Operations with Carry Bit

 

위에서 어떤 Computation 을 하는 Instruction 에 Postfix S 를 붙임으로써 Condition Code Flags 를 이용하였다.

예를 들어, SUBS    r2, r2, r0 ß S 를 붙여서 condition flags 세팅하였다. 다음 라인부터 이 Flags 를 이용가능하다.

 

이렇게 Flag를 Postfix S 를 이용하여 사용할 수 도 있지만, 아예 Computation 자체 결과에서 (다음 라인까지 갈 필요없이) Flag 를 세팅하여 그 Flag 값을 적용하기 위해서는 따로 S 를 붙일 필요없이 특정 Instruction 을 사용하면된다. ( 단, Carry out 에 관련된 C Flag 에 국한된다. ) 예를 들어, SBC    r3, r3, r1 ß SUB 연산을 하는 동시에 그에 대한 결과를 이용햐 C Flag 를 세팅하고 그렇게 세팅된 C Flag 를 SUB 연산의 결과에 바로 적용시킨다.

 

ADC r3, r3, r1               / ADC ADD + Carry bit 표현

                                / ADD 의 결과 값이 기본 32bits를 넘어설 경우 발생하는 Carry를 같이 표현해주기 위함.

 

ADD    r0, r1, r2            @ r0 ß r1 + r2

ADC    r0, r1, r2            @ r0 ß r1 + r2 + C    

 

SUB    r0, r1, r2            @ r0 ß r1 - r2

SBC    r0, r1, r2            @ r0 ß r1 - r2 + C - 1

 

RSB    r0, r1, r2            @ r0 ß r2 - r1

RSC    r0, r1, r2            @ r0 ß r2 - r1 + C - 1

 

  왜? Subtract 연산에서는 Carry Bit 를 붙여준 후에 1을 빼줄까?

 

- 뺼셈 연산은 실제로 컴퓨터 안에서는 2 진수들의 덧셈 연산을 이용하고 우리에게 뺄셈의 결과를 보여주는 것이다. 그렇게 해서 발생한 Carry bit 는 덧셈에 대한 Carry bit 일 수 밖에 없다. 이렇게 컴퓨터의 연산방법에 의하여 내제적인 Carry bit의 문제점을 없애서 바로 잡아야한다. 그래서 이 뺼셈을 수행하는 구조적인 문제에서 발생한 Carry bit 를 마지막에서 빼주어 없애기 위해 '-1' 연산을 하는 것이다.

 

 

이렇게 지금까지 산술 연산 (Arithmetic operation)에 대해 알아보았다.

다음은 Comparisons '비교' Instruction에 대해 알아보자.

 

 

 

 

 

 

Posted by 하늘_


 

Data Processing Instructions

Logical Operations

 

Data Processing Instructions 은 ARM instructions 중에 가장 커다란 집합체로 많은 연산들이 있다. 다 다루지는 않고, 꼭 필요한, 많이 사용하는 명령어들을 간단하게 알아볼것이다. 가장 큰 집합체인 만큼, Data Processing Instructions 에는 몇 개의 Operations 로 나누어진다. 그 중 처음으로 알아볼 것은 Logical operations 이다. 

 

시스템 프로그래밍 - 4 (1) : Data Processing Instructions - Logical operations

 

+ 모든 Data Processing Instructions 은 오직 레지스터에서만 실행된다. 절대로 메모리에서 실행되지 않는다.

 

 

 - Operation examples ( #5 는 '상수 number' 5 를 뜻한다. )

 

-    MOV    r0, r1         @ r0 ß r1

r1 에 있는 값을 r0 에 넣는다 

-    MVN    r0, #7        @ r0 ß ~ 7

MOV + NOT = #7 을 NOT 한 결과를 r0 에 넣는다

-    AND    r0, r1, r2     @ r0 ß r1 & r2 

r1 과 r2 를 AND 한 결과를 r0 에 넣는다

-    ORR    r0, r1, #6     @ r0 ß r1 | 6

r1 과 #6 를 OR 한 결과를 r0 에 넣는다

-    EOR   r0, r1, r2       @ r0 ß r1 ^ r2

r1 과 r2 를 XOR(=Exclusive OR) 한 결과를 r0 에 넣는다

-    BIC   r0, r1, #7       @ r0 ß r1 & ~ 7

Bit Clear 라는 개념으로, 7 이 [00000111] 인데, 1이 있는 자리에서는 무조건 0 의 결과가 나오며

0이 있는 자리는 위에 피연산자인 r1 의 결과가 그대로 내려온다. (0이면 0, 1이면 1)

01101001 = r1 값 : Bit Clear 는 필터 개념으로 이해하면 쉽다.

01010101 ( 0인 곳은 위에 값을 아래로 내려보낸다. )

00101000 = BIC 의 결과

 

 

 - Basic Instruction form

 

위에 나열된 Instructions 를 보면 일반적으로 XXX (연산, 작업의 이름) + r1, r3, r2 이런 형식을 가졌다는 것을 알아볼 수 있다. 얼핏 보기에는 그저 원하는 연산이나 작업에 따라 r0 이나 #3 같은 것들을 나열한 것으로 보일 수도 있으나, 꼭 지켜야만 하는 정형화된 형태가 있다.

 

컴퓨터는 알다시피 두뇌를 가진 인간처럼 능동적으로 생각할 수 없는 기계에 불과하기에, 항상 정형화된 형태 form 에 맞추어 컴퓨터에게 하나 하나 꼼꼼하게 알려주어야지 그때서야 컴퓨터는 작동을 올바르게 수행한다.

 

ARM Instruction 을 사용하기 위한 Format 은 각 Instruction 의 종류에 따라 각각 32 bits 의 사용 가능한 '방'이 주어진다. 이 '방'에는 그 Instruction 실행에 대한 여러 옵션들을 추가해줄 수 있다. 예를들어 단순한 '+' 덧셈 (빨강)Instruction 에 '어떠한 조건이 만족되면 + 덧셈', '+ 덧셈 후 맨 첫번째가 0인지 1인지', '꼭 무엇과 무엇을 덧셈 +' 등 Instruction을 실행하는데 필요한 '추가적인 조건(cond)', '피연산자(operand : rm, rn...)', '목적지(destination : rd)' 등등의 요소들이 담길 장소들이 이 32 bits 의 전체 방에 각 자신이 들어가야할 위치를 지니게 된다.

 

[ 32 비트 구성 그림의 예시 ]

 

우리는 이에 따라 반드시 각자 할당된 장소에 따라 그 장소에 알맞은 값들 (cond? rm? rn? rd?) 을 넣어야 한다. 

 

기본적인 instruction form을 단순하게 정리하자면 아래와 같다.

( ARM 에는 정말 많은 instruction set 들이 있으며, 그 중 한 set 이 우리가 이번 4 장에서 배우는

Data Processing set 이다. 아래의 format 은 Data Processing / PSR Transfer 에 대한 포맷일 뿐이다.

다른 set 에 대한 instruction format 을 알고싶다면 인터넷 검색, 서적들을 찾아보길 권장한다.)

[ Formats of ARM Instruction set : http://blog.naver.com/suyguy17?Redirect=Log&logNo=146022731 ]

 

XXX    rd, rm, op               rd : destination 목적 register 가 들어가야한다 ( ex. r1 )

                                    rn : source register

                                    rm : source register - First operand 피연산자 register

                                    op : Second operand 피연산자 무엇이든지 된다. Constant, register 등등

 

( MOV 와 MVN 은 First operand 가 없고, Second operand 만 있으므로, Constant, register 무엇이든지 사용가능 )

 

이렇게해서 기초적인 Logical Operations 와 Basic Instruction form 를 알아보았다.

다음 장 4 (2) 에서는 산술 연산들을 알아보자.

 

 

 

 

 

 

Posted by 하늘_


 

System Data Structure 을 기반으로 여러 Instruction들을 사용하여, 많은 실행, 동작들을 할 수 있다. ARM의 특징은 Load / Save 라고 배웠으며, 따라서 ARM의 모든 동작은 메모리로부터, 메모리에게 Load 와 Save 를 하면서 여러 연산들은 레지스터에서 처리한다. 그럼 이제부터 모든 Instructions 의 기본이 되는 Load 와 Save Instructions 을 알아보자.

 

 

Load / Store instructions

 

- Single register data transfer ( LDR / STR : Register )

 

-    STR r0, [ r5 ]        @ r0 := memory [r5] / 방향 >

 

à레지스터 r5 (r5, r0 들은 레지스터 번지 수를 뜻한다.)’ 안에는 메모리 주소 값이 있다. 주소가 0x30000000메모리레지스터 r0’ 안에 있는 값인 0x12345678 (16 data)을 저장한다. ( [ x ] x 의 주소를 갖는 메모리가 가지고 있는 값을 뜻한다.)

 

r5 = 0x30000000  @ r5 레지스터에 '0x30..' 값은 '메모리 주소 값'이다.

r0 = 0x12345678  @ r0 레지스터에 '0x12..' 값이 들어있다. 이를 'r5 의 값'을 주소로 갖는 메모리에 작성한다.

 

 

-    LDR r1, [ r5 ]        @ memory [r5] := r1 / 방향 <

 

à 위 STR 에 이어, 주소가 (r5의 값) 0x30000000 인 메모리에서 Single Register에 해당하는 1 워드( 32비트 단위 )를 레지스터 번지 수 r1 으로 읽어낸다. r1 에 r5 값을 주소로 갖는 메모리에 있던 값이 들어간다.

 

r5 = 0x30000000 @ r5 레지스터에 '0x30..' 값은 '메모리 주소 값'이다.

r1 = 0x12345678 @ 'r5 의 값'을 주소로 갖는 메모리에 있는 값을 r1 레지스터에 넣는다.

 

 

 

 

- Block data transfer ( LDM / STM : Multiple  )

 

-    STMIA r0, { r2 - r9 }     move the words to mem[r0] / 방향 <

 

à STR 하고 하는 일은 유사하지만, 어디서 어디로 저장하는지에 대한 방향이 틀리다. r0 이 값을 받아내거나, 보류하는 기능을 하는 레지스터가 아니라 메모리 주소를 가리키는 포인터이다. LDMIA도 마찬가지이다. 그냥 STR 에서는 싱글 레지스터에 해당하는 작은 값 (단지 1 Word = 32 bits)을 저장하는 것이 아니라, { r2 에서 r9 까지 }의 8개의 words를 읽어서 r0 이 갖고 있는 '메모리 주소 값'이 가리키고 있는 메모리에 순차적으로 저장한다. 

 

r0 = 0x30000000    @ r0 레지스터에 '0x30..' 라는 '메모리 주소 값'을 갖는다.

이 r0 값이 가리키는 메모리부터 순서대로 8 words 만큼 저장하게 된다.

{ r2 - r9 }             @ r2 부터 r9 까지의 레지스터에 저장 되어있는 8 words 만큼을 읽어낸다.

 

 

-    LDMIA r1, { r2 - r9 }             @ move 8 words at mem[r0] ( MIA : Multiple In Array ) / 방향 >

 

à 8개 레지스터에 저장될 내용(8 words)을 r1이 가리키는 주소로부터 읽어내어 r2, r3, r4, ... , r9 에 저장한다. 방향이 LDR 과는 달리 반대 방향이다. 자세히 설명하자면, r1 이 값을 받아내거나, 보류하는 기능을 하는 레지스터가 아니라 메모리 주소를 갖는 포인터와 같은 개념이다. STMIA도 마찬가지이다.

 

r1 = 0x30000000    @ r1 레지스터에 '0x30..' 라는 '메모리 주소 값'을 갖는다.

이 r1 값이 가리키는 메모리부터 순서대로 8 words 만큼을 읽어내게 된다.

{ r2 - r9 }             @ r2 부터 r9 까지의 레지스터에 r1이 가리키는 메모리부터 8 words 만큼을 읽어 저장한다.

 

 

 

 

- Single Data Swap ( SWP )

 

-    Used for semaphore implementation

     SWP{cond} {B} Rd, Rm, [ Rn ]    @ Rd := [ Rn ], [ Rn ] := Rm

 

 

 

 

Load / Store for Bytes or Half-words

 

-    LDRB r1, [ r2 ]        r1 := mem[r2] In Byte / 방향 <

-    STRB r3, [ r4 ]        mem[r4] := r3 In Byte / 방향 >

 

-    LDRH r1, [ r2 ]        @ r1 := mem[r2] In Unsigned Short / 방향 <

-    STRH r3, [ r4 ]        @ mem[r4] := r3 In Unsigned Short / 방향 >

 

-    LDRSH r1, [ r2 ]      @ r1 := mem[r2] In Signed Short / 방향 <

-    STRSH r3, [ r4 ]      @ mem[r4] := r3 In Signed Short / 방향 >

 

Signed and Unsigned Integer

 

 

 

 

 

 

 

 

 

Posted by 하늘_