ARM Applications


 
* Update history

- 2012.11.15 : 초기 Release



 
2. 어셈블리어 실습
   2.1 ARM Simulator 환경 설정
   2.2 Data Processing Instructions
   2.3 Multiply Instructions
   2.4 Load/Store Instructions
   2.5 Load/Store Multiple Instructions
   2.6 Branch Instructions
   2.7 Status Register Access Instructions
   2.8 Conditional Execution


 
2장에서는 주로 실습을 위주로 진행 하도록 하겠습니다. 실제 개발보드를 활용해도 되겠으나 어셈블리어 실습은 ARM Simulator 를 활용해서 진행하는 것이 효율 적이기 때문에 IAR 컴파일러에서 Simulator 상에서 진행을 하도록 하겠습니다.

2. 어셈블리어 실습

2.1 ARM Simulator 환경 설정

IAR ARM용 컴파일러는 가격이 그렇게 싸지는 않습니다. 다행히도 www.iar.com 에서 시간제한(30일), 사이즈제한(32Kbyte) 버젼을 다운 받아서 사용해 볼 수 있습니다.

2.1.1 IAR Evaluation 버젼 다운로드

- 다운로드 사이트 방문
http://supp.iar.com/Download/SW/?item=EWARM-EVAL



패키지 사이즈가 약 830MB정도 입니다. 다운 받아서 설치 하시기 바랍니다.

다음은 Evaluation 버젼을 다운로드 받기 위한 절차데로 화면을 캡쳐해 놓은 것입니다. 참조하시기 바랍니다.



반드시 "Code size limited" 를 선택 하시기 바랍니다. 그렇지 않으면 30일 이후에 더이상 IAR 컴파일러를 사용할 수 없게 됩니다.

(2) IAR Evaluation 버젼 설치



설치가 완료되면 마지막에 License 를 입력하는 화면이 나옵니다. 여기에서 "Register with IAR System to get an evaluation license" 를 선택 하시기 바랍니다.



현재 설치된 제품중에 라이센스가 없는 제품의 리스트가 나옵니다. 선택을 하고 "다음" 으로 진행 합니다.



IAR Evaluation 버젼을 다운받기 위해서 입력했던 Email 주소로 Registeration Confirm 메일이 와있을 것입니다.
Confirm 메일에 엤는 Confirm 링크를 클릭하면 "Rgistration Complete" 와 함께 Evaluation License 번호를 알수가 있습니다. 그 번호를 위의 화면의 빈 칸에 입력하고 나서 "Regiser" 버튼을 누르면 잠시후에 네트워크를 통해서 Evaluation 라이센스 번호를 받게 됩니다. 경우에 따라서 Fail 이라는 메세지가 나올수도 있습니다. 그때는 "Register" 버튼을 다시한번 클릭해서 재 시도해 보시기 바랍니다.





모든 설치가 완료된 화면 입니다.

2.1.2 ARM Simulator 프로젝트 생성

아래 화면데로 따라서 ARM Simulator 기반의 실습 프로젝트를 생성해 보시기 바랍니다.

(1) Create New Project



(2) Empty project 생성



(3) 프로젝트 파일이름 입력 - "arm_simulator"





(4) 그룹생성 - "base", "testcode" 그룹 생성





(5) 소스 파일추가



- "base" 그룹 : 2440init_ewarm.s 추가
- "testcode" 그룹 : main.c, SegInit.c 추가

(6) 프로젝트 옵션 설정



(6.1) Target Device 설정 : Samsung S3C2440A 로 설정 합니다.





(7) Processor Mode 설정 : "ARM" 모드로 설정 합니다.



(8) Scattor Loading 파일 설정 : 프로젝트 디렉토리에 "arm_simulator.icf" 파일을 선택 합니다.



(9) Program Start Entry 설정 : "__program_start" 라고 입력 합니다.



(10) 디버깅 정보를 포함하도록 설정 합니다.



(11) Map 파일을 생성 하도록 합니다.



(12) Debugger 정보 설정 : Dirver - Simulator, Run to main 은 반드시 설정 해제 합니다.



2.2 Data Processing Instructions

2장에서는 ARM Simulator를 활용한 어셈블리어 실습을 해보도록 하겠습니다. 이 내용들은 ARM Architecture Instruction 의 이론 부분을 설명할때 한번씩 나왔던 내용입니다. 여기서는 이론으로 공부했던 내용들을 실제로 ARM Simulator에서 코드를 작성한 후 컴파일하고 실행해서 결과값을 직접 확인해 보는데 의미가 있습니다.

R0 = 0x00
R1 = 0x22
R2 = 0x02
R3 = 0x00
R4 = 0x00


레지스터 값이 위와 같을때 아래 예제들을 차례대로 수행해 보세요.

(1) AND R0, R0, #0xFF

2440init_ewarm.s 파일에 다음과 같이 입력을 합니다.


SECTION IMAGE_STARTUP:CODE (2)
PUBLIC __program_start
CODE32

__program_start
      b ResetHandler
      b HandlerUndef ;handler for Undefined mode
      b HandlerSWI ;handler for SWI interrupt
      b HandlerPabort ;handler for PAbort
      b HandlerDabort ;handler for DAbort
      b . ;reserved
      b HandlerIRQ ;handler for IRQ interrupt
      b HandlerFIQ ;handler for FIQ interrupt

ResetHandler
      MOV R0, #0x00
      MOV R1, #0x22
      MOV R2, #0x02
      MOV R3, #0x00
      MOV R4, #0x00

      AND R0, R0, #0xFF
      ADD R0, R0, #1

      ADD R0, R0, R1
      LSL R1, R0, #2
      SUB R3, R2, R1, LSR R2

HandlerFIQ
      b .


HandlerIRQ
      b .

HandlerUndef
      b .


HandlerSWI
      b .


HandlerDabort
      b .


HandlerPabort
      b .


END



- 실행 결과


(2) ADD R0, R0, #1 ; R0 = R0 + 1 = 0x1

- 실행결과



(3) ADD R0, R0, R1 ; R0 = R0 + R1 = 0x01 + 0x22 = 0x23

- 실행결과



(4) LSL R1, R0, #2 ; 0x23(100011) LSL #2 = 0x8C(10001100) -> 참고로 왼쪽으로 2번 쉬프트 하면 *4 를 한것과 같습니다.

- 실행결과



(5) SUB R3, R2, R1, LSR R2

- 실행결과



R3의 값이 0xFFFFFFDF 로 복잡한 값이 나왔습니다. 왜 이런 결과가 나왔을까요 ?
우선 R1을 오른쪽으로 2번 쉬프트 시키면 0x23이 되고 R2(0x02) 에서 R1(0x23) 을 빼면 결과값이 -0x21가 되고 이 값을 2의 보수로 표시하면
0xFFFFFFDF 가 됩니다.

  0x21 = 00000000000000000000000000100001
-0x21 = 11111111111111111111111111011111 --> 0x21의 2의 보수

참고로 2의 보수를 취하는 방법은 원래의 2진수에서 0->1, 1->0 으로 바꾼후에 1을 더하면 되겠지요.

2.3 Multiply Instructions

R0 = 0x01
R1 = 0x02
R2 = 0x03
R3 = 0x04


레지스터 값이 위와 같을때 아래 예제들을 차례대로 수행해 보세요.


(1) MUL R2, R0, R1 ; R2 = R0*R1 = 0x02

2440init_ewarm.s 파일에 다음과 같이 입력을 합니다.

ResetHandler
      MOV R0, 0x01
      MOV R1, 0x02
      MOV R2, 0x03
      MOV R3, 0x04

      MUL R2, R0, R1
      MULS R2, R0, R1
      MLA R3, R2, R1, R0

- 실행결과



(2) MULS R2, R0, R1 ; R2 = R0*R1 = 0x02

MUL 명령과 같은 명령입니다. 하지만 MUL뒤에 "S" 가 붙으면 명령어 처리가 끝난 이후에 CPSR의 Flag Field 가 연산 결과에 따라서 업데이트가 됩니다.

- 실행결과



(3) MLA R3, R2, R1, R0 ; R3 = R2*R1 + R0

참 효율적이네요. 명령어 하나로 곱하기 연산과 더하기 연산을 같이 할 수 있습니다.

- 실행결과



2.4 Load/Store Instructions

2.4.1 Pre-index

R0 = 0x31000000
R1 = 0x00
R2 = 0x00


(1) LDR R1, [R0] ; R1 <-- M[R0]

2440init_ewarm.s 파일에 다음과 같이 입력을 합니다.

ResetHandler
      MOV R0, #0x31000000
      MOV R1, #0x0
      MOV R2, #0x0
      LDR R3, =0x01234567
      STR R3, [R0]
      LDR R3, =0x89abcdef
      STR R3, [R0, #4]

      LDR R1, [R0]
      STR R1, [R0, #4]
      STR R1, [R0, #4]!


- 실행결과



(2) STR R1, [R0, #4] ; R1 <-- M[R0+4]



(3) STR R1, [R0, #4]! ; R1 <-- M[R0+4], then R0 <-- R0+4

- 실행결과



2.4.2 Post-index

R0 = 0x31000000
R1 = 0x00
R2 = 0x04


(1) LDR R1, [R0], R2 ; R1 <-- M[R0], then R0 <-- R0+R2

ResetHandler
      MOV R0, #0x31000000
      MOV R1, #0x0
      MOV R2, #0x4
      LDR R3, =0x01234567
      STR R3, [R0]
      LDR R3, =0x89abcdef
      STR R3, [R0, #4]

      LDR R1, [R0], R2
      STR R1, [R0], #4



- 실행결과



(2) STR R1, [R0], #4 ; R1 <-- M[R0], then R0 <-- R0+4

- 실행결과



2.5 Load/Store Multiple Instructions

R0 = 0x000A

R4 = 0x000B

R5 = 0x000C

R13 = 0xFFF0


(1) STMIA R13!, {R0,R4-R5}

ResetHandler
      MOV R0, #0x000A
      MOV R4, #0X000B
      MOV R5, #0x000C
      LDR R13, =0xFFF0

      STMIA R13!, {R0,R4-R5}


- 실행결과



(2) STMIB R13!, {R0,R4-R5}

ResetHandler
      MOV R0, #0x000A
      MOV R4, #0X000B
      MOV R5, #0x000C
      LDR R13, =0xFFF0

      STMIB R13!, {R0,R4-R5}



- 실행결과



(3) STMDA R13!, {R0,R4-R5}

ResetHandler
      MOV R0, #0x000A
      MOV R4, #0X000B
      MOV R5, #0x000C
      LDR R13, =0xFFF0

      STMDA R13!, {R0,R4-R5}


- 실행결과



(4) STMDB R13!, {R0,R4-R5}

ResetHandler
      MOV R0, #0x000A
      MOV R4, #0X000B
      MOV R5, #0x000C
      LDR R13, =0xFFF0

      STMDB R13!, {R0,R4-R5}


- 실행결과


2.6 Branch Instructions

ResetHandler

subsequent
      MOV R0, #1
      MOV R1, #2
      BL func1
      ADD R2, R0, R1

func1
      MOV R0, #3
      MOV R1, #4
      BL func2
      ADD R2, R0, R1
      MOV PC, LR

func2
      MOV R0, #5
      MOV R1, #6
      ADD R2, R0, R1
      MOV PC, LR


위의 예제를 실행하면 R2 레지스터에 "3" 이 저장이 되지 않습니다.
R2 레지스터에 "3" 이 저장이 될 수 있도록 예제를 수정해 보시기 바랍니다. 수정한 예제 코드는 아래와 같습니다.



서브 함수를 호출 할 경우에는 서브 함수에서 사용하는 레지스터와 LR 레지스터를 반드시 저장한 이후에 사용해야 한다는 것을 알 수 있습니다.
이것을 다르게 말하면 Context switch 라고 이야기 할 수 있습니다.

2.7 Status Register Access Instructions


소프트웨어 구성

ResetHandler
      MRS R0, CPSR
      BIC R0, R0, #0x80 ; 7번 비트를 clear 하면 인터럽트가 활성화 됩니다.
      MSR CPSR, R0


- 실행 결과

소프트웨어 구성

2.8 Conditional Execution

지금까지 배운 모든 어셈블리어들을 활용해서 최종적으로 몇가지 예제를 풀어 보도록 하겠습니다. 예제를 구현하는데에는 여러가지 방법들이 많이 있겠지만 가장 최적화된 어셈블리 명령어를 사용하시기 바랍니다.

(1) 1 ~ 10을 더하는 최적화된 어셈블리어로 작성해 보세요.

ResetHandler
       MOV R5, #10
       MOV R6, #0
loop_sum
       ADD R6, R6, R5
       SUBS R5, R5, #1
       BNE loop_sum ; Not Equal(Z=1)


루프를 사용할 경우에는 거꾸로 도는것이 효율적 입니다.

(2) 2개 변수사이의 절대값을 구하세요.

- [-2 and 3] 사이의 절대값

ResetHandler
       MOV R0, #-2
       MOV R1, #3

       SUBS R0, R0, R1
       RSBMI R0, R0, #0

소프트웨어 구성

"SUBS R0, R0, R1" 명령을 실행 했을때의 그림 입니다. R0, CPSR의 "N" Flag 를 잘 살펴 보시기 바랍니다. 참고로 RSBMI 명령어는 CPSR의 "N" Flag 가 Set 되어 있을때 뻴셈을 하는데 SUB 명령과는 연산의 방향이 반대로 수행이 되는 명령어 입니다. 그러니까 이번 예제에서는 "#0" 에서 "R0" 를 빼는 것입니다.

소프트웨어 구성

- [3 and 1] 사이의 절대값

ResetHandler
       MOV R0, #3
       MOV R1, #1

       SUBS R0, R0, R1
       RSBMI R0, R0, #0

"SUBS R0, R0, R1" 명령을 실행 했을때의 그림 입니다. R0, CPSR의 "N" Flag 를 잘 살펴 보시기 바랍니다.

소프트웨어 구성