ARM 프로세서 명령어 소개

2022. 12. 11. 13:14임베디드 시스템 설계/ARM

-      ARM 명령어

메모리 접근 명령어

Load / Store

연산의 대상으로 외부 메모리를 직접 사용하지 못합니다.

외부 메모리는 반드시 레지스터를 거쳐서 연산이 이루어집니다.

메모리 > 레지스터 : LDR(Load to register)를 이용합니다.

레지스터 > 메모리: STR(Store to memory)를 이용합니다.

 

레지스터 간접 참조

Ldr Rd, [Rs]

Rd = [Rs]입니다. Rs의 레지스터 값을 메모리 주소로 하여 내용을 Rdload 시켜주는 참조 방식입니다.

Rs, Rd : r0 – r15입니다.

또 다른 레지스터 간접 참조의 예

LDR r0, [r1] > r10x100번지를 로드하여 r0 레지스터에 로드합니다.

STR r0, [r1] > r10x100번지에 R0 레지스터값을 저장합니다.

LDR r0, = 0x1000

LDR r1, = 80

STR r1, [r0]

LDR r1, [r0]

 

LDR, STR로 메모리 접근시 주소는 반드시 4B align 필요합니다.

데이터처리 명령어

레지스터 안에서 데이터를 조작하는데 사용됨

데이터 이동연산이 가능합니다. (MOV / MVN)

산술 연산이 가능합니다. (ADD / ADC / SUB / SBC / RSB / RSC)

논리 연산이 가능합니다. (AND / ORR / EOR / BIC)

 

레지스터 안에서 데이터를 조작하는데 사용됨

비교연산

CMP / CMN / TST / TEQ

곱셈 연산 MUL / UMULL / UMLAL / SMULL / SMLAL

 

명령어 길이 : 32- 비트

형식 : 3-address format로 사용됩니다.

한 사이클 안에 실행됩니다.

조건부 실행이 가능합니다.

그 결과가 상태 플래그에 영향을 주지 않습니다. (‘S’ 접미사 사용)

 

MOV 명령어

MOV : Move

32비트 값을 레지스터로 이동시킵니다.

표기법

1.     MOV<cond>{S} <Rd>, #<rotated_immed>

2.     MOV<cond>{S} <Rd>, <Rm>{, <shift>}

 

배럴 시프터

배럴 시프터(Barrel shifter)

A digital circuit that can shift a data word by a specified number of bits in one clock cycle

ARM에서 데이터처리 명령에 의해 사용되기 전에 배럴 시프터로 미리 시프트 처리 한 후, 그 결과값을 Rm으로 사용 가능합니다.

(MOV<cond>{S} <Rd>, <Rm> {, <shift>})

배럴 시프터를 사용할 수 없는 데이터 처리 명령도 있습니다.

(MUL(multiply), CLZ(count leading zero), QADD(signed saturated 32-bit add))

선처리나 시프트 작업은 한 명령어 실행 사이클 내에서 처리됩니다.

상수값을 레지스터로 로드하여 2의 거듭자리만큼 곱하거나 나눌 때 특히 유용합니다.

 

MVN 명령어

MVN : Move NOT

32비트 값을 논리 반전 시킵니다.

뒤의 값을 1’s compliment 취해서 연산합니다.

표기법은

1.     MVN<cond>{S} <Rd>, #<rotated_immed>

2.     MVN<cond>{S} <Rd>, <Rm>{, <shift>}

 

0

ARM 명령어 예제 사례

Keil MDK IDE 동작 assemble 사례를 알아봅시다.

 

-      ARM 상수 표현 방법

상수 표현

#상수의 구성

32비트 명령어내에 상수 값을 함께 저장합니다. 이떄 범위 제한이 발생합니다.

8비트 값과 짝수비트 ROR(Rotate Right)로 표현되는 값입니다.

0-255 범위의 상수는 무조건 가능합니다.

 

#상수의 구성

다음에 사용된 상수의 validaty를 판단합니다.

Mov r0, #0x7f00

Mov r0, #0x30c0

Mov r0, #0x3f000000

Mov r0, #12345678

Mov r0, #0x14e

범위 제한 없는 32비트 값으로 표현 가능합니다.

실제 상수 값은 메모리에 존재하며 레지스터 참조로 변환됩니다.

 

 

(32비트 명령어 구조에서 상수가 32비트 표현이 가능한지? : ldr r0, = 12345678)

어셈블 후 역 어셈블하여 결과 확인합니다.

0x00000038 : LDR r0, 0x54

(명령어에 포함 못하므로 상수를 만들고 그 주소를 이용하여 access합니다.)

0x0000003c : MOV r1, #0x1000

(0x1000 mov 명령어에 포함가능한 상수이므로 LDRMOV로 변환합니다.)

0x00000040 : STR r0, [r1, #0]

0x00000054 : DCD 12345678

 

산술 명령어 : ADD

32비트 signed / unsigned 값의 덧셈과 뺼셈 등을 구현합니다.

ADD : Add

32 비트 값의 덧셈을 의미합니다.

표기법

1.     ADD<cond>{S} <Rd>, <Rn>, #<rotated_immed>

2.     ADD<cond>{S} <Rd>, <Rn>, <Rm>{, <shift>}

 

(인라인 배럴 시프터가 사용되어 표현할 수 있습니다.)

 

인라인 배럴 시프터를 활용한 산술연산으로 ARM 명령어 세트에서 매우 강력한 특징입니다.

 

ADC : Add with carry

캐리를 고려한 두 32비트 값의 덧셈

표기법

1.     ADC<cond>{S} <Rd>, <Rn>, #<rotated_immed>

2.     ADC<cond>{S} <Rd>, <Rn>, <Rm>{, <shift>}

 

산술 명령어 : SUB

SUB : subtract

32 비트 값의 뺼셈

표기법

1.     SUB<cond>{S} <Rd>, <Rn>, #<rotated_immed>

2.     SUB<cond>{S} <Rd>, <Rn>, <Rm>{, <shift>}

 

 

산술명령어 : SBC

SBC : Subtract with carry

캐리를 고려한 두 32비트 값의 뺄셈입니다.

표기법

1.     SBC<cond>{S} <Rd>, <Rn>, #<rotated_immed>

2.     SBC<cond>{S} <Rd>, <Rn>, <Rm>{, <shift>}

 

산술 명령어 (64비트 연산)

64비트 덧셈, 뺄셈을 위한 코드 [R3:R2] +/- [R1:R0]

Carry : flagC비트, rotate때는 C비트가 rotate에 포함

덧셈연산시 자리올림 발생시 set, 뺄셈연산시 빌림(borrow) 발생시 clear

R3 : 0x11111111 R2 : 0x88888888

ADD R4, R2, R0

ADC R5, R3, R1

SUBS R4, R2, R0

SBC R5, R3, R1

S-suffix를 붙여야 합니다!!

 

S-suffix 적용 연산(상태 플래그 반영)

S-suffix

연산 후 상태 register에 결과를 반영합니다.

상태 flag를 갱신하지 않도록 하면 분기 최소화에 도움이 됩니다.

대상

데이터 이동 명령 : MOV, MVN

산술 연산 : ADD, SUB, ADC, SBC, RSB, RSC

논리 연산 : AND, EOR, ORR, BIC

곱셈명령군 : MUL, MLA, UMULL, UMLAL, SMULL, SMLAL