Skip to content
KyuHyuk Blog

ARM Assembly 기초


Load, Store

MOV 명령

상수 값을 레지스터에 저장

상수 표현

사용된 상수가 MOV 명령에서 사용 가능한지 불가능한지 판단해보자

MOV보다 LDR이 느리지만, LDR은 32비트 데이터를 사용할 수 있습니다.

레지스터 간접참조 LDR, STR

예)

  LDR R0, =0x1000   @ R0에 상수 0x1000 저장
  LDR R1, =80       @ R1에 상수 80 저장
  STR R1, [R0]      @ R0의 값인 0x1000를 메모리 주소로 참조하여
                    @ 0x1000에 상수 80을 저장

LDR, STR 쉽게 이해하는 방법

LDR, STR 쉽게 이해하는 방법

Label

START:  MOV R0, #10       @ R0 레지스터에 상수 10을 저장
        STR R0, [R1]      @ R1에 저장되어 있는 주소에 R0 값을 저장
        LDR PC, =START    @ START의 주소를 PC(Program counter)에 저장

LDR, STR Post Indexing

Post Indexing 사용 방법:

  LDR R0, [R1], #4            @ R1 주소에 있는 값을 R0에 넣고, R1에 4를 더합니다.
  STR R0, [R2], #-4           @ R0의 값을 R2의 주소에 넣고, R2에 4를 뺍니다.
  LDR R0, [R1], R3            @ R1 주소에 있는 값을 R0에 넣고, R1에 R3의 값을 더합니다.
  STR R0, [R2], -R3           @ R0의 값을 R2의 주소에 넣고, R2에 R3의 값을 뺍니다.
  LDR R0, [R1], R3, LSL #2    @ R1 주소에 있는 값을 R0에 넣고,
                              @ R1에 R3, LSL #2한 값을 더합니다.
  STR R0, [R2], -R3, ASR #2   @ R2 주소에 있는 값을 R0에 넣고,
                              @ R2에 R3, ASR #2한 값을 뺍니다.

예)

  LDR R1, 0x1000              @ R1에 상수 0x1000을 넣습니다.
                              @ R1 : 0x1000

  LDR R0, [R1], #4            @ R0에 0x1000를 참조한 값(R1의 메모리 참조주소)을 넣고,
                              @ R1에 4를 더합니다.
                              @ R1 : 0x1004

  LDR R2, [R1], #4            @ R2에 0x1004를 참조한 값(R1의 메모리 참조주소)을 넣고,
                              @ R1에 4를 더합니다.
                              @ R1 : 0x1008

LDR, STR Pre Indexing

Pre Indexing 사용 방법:

  LDR R0, [R1], #4            @ R1에 4를 더한것을 참조하여 R0에 넣습니다.
  STR R0, [R2], #-4           @ R0의 값을 R2에 4를 뺀 주소에 넣습니다.
  LDR R0, [R1], R3            @ R1에 R3의 값을 더한것을 참조하여 R0에 넣습니다.
  STR R0, [R2], -R3           @ R0의 값을 R2에 R3의 값을 뺀 주소에 넣습니다.
  LDR R0, [R1], R3, LSL #2    @ R1에 R3, LSL #2한 값을 더한뒤,
                              @ 주소에 있는 값을 R0에 넣습니다.
  STR R0, [R2], -R3, ASR #2   @ R2에 R3, ASR #2한 값을 뺀뒤,
                              @ R0의 값을 변경된 주소로 넣습니다.

예)

  LDR R1, 0x1000              @ R1에 상수 0x1000을 넣습니다.
                              @ R1 : 0x1000

  LDR R0, [R1, #4]            @ R1에 4를 더한 주소의 참조한 값(0x1004)을 R0에 넣습니다.
                              @ R1 : 0x1000

  LDR R2, [R1, #4]            @ R1에 4를 더한 주소의 참조한 값(0x1004)을 R2에 넣습니다.
                              @ R1 : 0x1000

Pre Indexing에서는 값이 업데이트 되지 않습니다! 만약 값을 업데이트하고 싶다면 아래의 !(Auto Update) 옵션을 사용해야합니다.

!(Auto Update) suffix’ 사용 예시)

  LDR R1, 0x1000              @ R1에 상수 0x1000을 넣습니다.
                              @ R1 : 0x1000

  LDR R0, [R1, #4]!           @ R1에 4를 더한 주소의 참조한 값(0x1004)을 R0에 넣습니다.
                              @ ! suffix가 있으므로, 자동으로 값이 업데이트 됩니다.
                              @ R1 : 0x1004

  LDR R2, [R1, #4]            @ R1에 4를 더한 주소의 참조한 값(0x1008)을 R2에 넣습니다.
                              @ ! suffix가 없으므로, 자동으로 값이 업데이트 되지 않습니다.
                              @ R1 : 0x1004

LSL, LSR Shift

ASR Shift


비트제어 명령어

다양한 비트연산

Example 4

  LDR R0, =0x1000           @ R0에 상수 0x1000을 넣습니다.
  LDR R1, [R0]              @ R1에 R0을 참조한 값을 넣습니다.
  BIC R1, R1, 0xF << 4      @ '1111'을 4번 Left Shift하면 '11110000'가 됩니다.
                            @ BIC로 R1의 4~7 비트를 0으로 설정합니다.
  ORR R1, R1, 0xA << 4      @ '1010'을 4번 Left Shift하면 '10100000'가 됩니다.
                            @ ORR로 R1의 5, 7번 비트를 1로 설정합니다.
  STR R1, [R0]              @ R1의 데이터를 R0에 저장되어있는 메모리주소에 저장합니다.

분기 명령어


비교 연산 명령어

비교연산은 레지스터에 변화가 없으며, Flag만 변합니다.

  AND R0, R0, #1 << 7
  CMP R0, #0
  MOVEQ R1, #3
  MOVNE R1, #2
  TST R0, #1 << 7
  MOVEQ R1, #3
  MOVNE R1, #2

CPSR(상태레지스터)과 Flag

CPSR - https://www.wikinote.org/Main/Savitribai-Phule-Pune-University/ENTC/AP-TE/Unit-1/Registers-CPSR-SPSR/

비교 연산을 할때는 NZCV만 사용한다

Carry는 덧셈을 했을때 범위를 초과해서 자리 올림이 발생했을때를 말하는것입니다. Overflow와는 다릅니다.

상태 플래그와 조건

  CMP R0, R1
  B□□ LOOP

□ 부분에 아래의 16가지 조건식이 들어가게 됩니다.

약어Flag 상태
EQEqual / Equals zero (False)Z set
NENot Equal (True)Z clear
CS/HSCarry Set / Unsigned higher or sameC set
CC/LOCarry Clear / Unsigned LowerC clear
MIMinus / NegativeN set
PLPlus / Positive or zeroN clear
VSOverflowV set
VCNo OverflowV clear
HIUnsigned higherC set and Z clear
LSUnsigned lower or sameC clear and Z set
GESigned greater then or equalN equals V
LTSigned less thanN is not equals V
GTSigned greater thanZ clear and N equals V
LESigned less than or equalZ set or N is not equal to V
ALAlwaysAny state
NVNeverNone

산술 명령어

일정 횟수를 반복하는 프로그램

  1. for(i=0; i<10; i++) 방식
  MOV R0, #0
1:
  @ 이곳에 코드 작성

  ADD R0, R0, #1
  CMP R0, #10
  BLT 1b
  1. for(i=10; i>0; i--) 방식
  MOV R0, #10
1:
  @ 이곳에 코드 작성

  SUB R0, R0, #1
  CMP R0, #0
  BGT 1b

위의 두 방법도 좋지만, Down Count 방식에 S-Suffix를 사용하는게 더 효율적입니다.

  MOV R0, #10
1:
  @ 이곳에 코드 작성

  SUBS R0, R0, #1
  BGT 1b

서브루틴 호출

서브루틴 호출과 복귀


특수용도 레지스터

레지스터설명용도
SP / R13Stack PointerC언어 사용시 스택의 주소를 저장
LR / R14Link Register함수 호출 시 되돌아갈 함수의 주소가 저장
PC / R15Program Counter프로그램 수행 시 읽어오는 명령의 주소를 저장
CPSRCurrent Program Status Register연산결과, IRQ, FIQ금지, 동작모드 등을 저장

Share this post:

Previous Post
Raspberry Pi Bare Bones
Next Post
React를 사용한 나만의 모바일 청첩장 개발 후기