임베디드 레시피

Egloos | Log-in





우리는패밀리 (ARM, THUMB, Coprocessor, NEON)

504 우리는 패밀리(ARM, THUMB, Coprocessor, NEON)

 

뭘 알아야 이해를 하지
ARM core는 32bit ARM 어셈블리 명령어와 16bit THUMB 어셈블리 명령어로 구별할 수가 있답니다. 컴파일 할 때 옵션을 어떻게 주느냐에 따라 ARM/THUMB 명령어로 나누어 진답니다. CPSR이나 SPSR과 같은 특별한 레지스터를 조절해야 하는 경우에는 반드시 ARM 명령어를 사용해야 하죠. 이 뿐만 아니라 Co-processor의 레지스터 값을 읽거나 쓸 때, NEON 명령어 같은 경우에도 ARM 명령어를 사용한답니다. 이제 이러한 명령어에 대해 자세히 알아보죠.

 

ARM 명령어
32bit로 이루어진 명령어는 아주 많이 있답니다. core에 따라 명령어 개수는 달라지는데, 최근에 나온 core일 수록 명령어 수는 더 많아 진답니다. 이러한 명령어는 몇 개의 type으로 나눌 수가 있답니다.

Data Processing ADD, ADC, SUB, SBC, RSB, RSC, AND, ORR, BIC, MOV, MVN, CMP, CMN, TST, TEQ …
Multiply MUL, MLA, SMULL, SMLAL, SMULL, UMLAL …
Load / Store LDR, LDRB, LDRBT, LDRH, LDRSB, LDRSH, LDRT, STR, STRB, STRBT, STRH, STRT …
PSR Transfer MSR, MRS …
Branch B, BL, BX …
Coprocessor MRC, MCR, LDC, STC …

하드웨 디버거를 이용해서 어셈블리 명령어들을 테스트 해 보도록 하죠.어셈블리 명령어를 넣으려면 데이타를 언제든지 읽고 쓰기가 가능해야 하니 SDRAM에 올리기로 하죠. 그러기 위해서는 타겟의 SDRAM 초기화시키는 스크립트를 만들어야 해요. 스크립트를 만들 때는 SDRAM 초기화를 하는 Startup.s 소스를 참고해서 만든답니다.
 

▶코드 Startup.s

sdram_initial:
                   @ Set memory control registers
                   ldr r0,=SMRDATA
                   ldr r1,=BWSCON         @ BWSCON Address
                   add r2, r0, #52           @ End address of SMRDATA
B5:
                   ldr r3, [r0], #4
                   str r3, [r1], #4
                   cmp r2, r0
                   bne B5
SMRDATA:
                  .word 0x22555112    @ BWSCON
                  .word 0x00000700    @ GCS0
                  .word 0x00007ff0     @ GCS1
                  .word 0x00000700   @ GCS2
                  .word 0x00007ff0     @ GCS3
                  .word 0x00000700   @ GCS4
                  .word 0x00000700    @ GCS5
                  .word 0x00018005   
                 @ GCS6, SDRAM (MT=3(SDRAM),Trcd=01(3Clock),SCAN=01(9Bit))
                  .word 0x00018005
                 @ GCS7, SDRAM (MT=3(SDRAM),Trcd=01(3Clock),SCAN=01(9Bit))
                  .word 0x008e0459
                  @Refresh(REFEN=1, TREFMD=0, Trp=3, Trc=5, Tchr=3)
                  .word 0x00000032
                   @ Bank Size, 32MB/32MB
                   .word 0x00000030
                   @ MRSR 6(CL=3)
                   .word 0x00000030 @ MRSR 7(CL=3)

하드웨어 디버거에서 사용할 스크립트를 아래와 같이 작성을 해 보죠.

▶코드 sdram_initial.cmm

     B::
          SYSTEM.RESET
          SYSTEM.CPU ARM920T
          SYSTEM.UP
          data.set 0x48000000 %long 0x22555112 ; BWSCON
          data.set 0x48000004 %long 0x00000700 ; GCS0
          data.set 0x48000008 %long 0x00007ff0 ; GCS1
          data.set 0x4800000C %long 0x00000700 ; GCS2
          data.set 0x48000010 %long 0x00007ff0 ; GCS3
          data.set 0x48000014 %long 0x00000700 ; GCS4
          data.set 0x48000018 %long 0x00000700 ; GCS5
          data.set 0x4800001C %long 0x00018005 ; GCS6
          data.set 0x48000020 %long 0x00018005 ; GCS7
          data.set 0x48000024 %long 0x008e0459 ; Refresh
          data.set 0x48000028 %long 0x00000032 ; Bank Size
          data.set 0x4800002C %long 0x00000030 ; MRSR 6
          data.set 0x48000030 %long 0x00000030 ; MRSR 7
          register.set pc 0x30000000
          data.list register
          ENDDO
 

하드웨어 디버거에서 스크립트를 실행했다면 이제 SDRAM 접근이 가능해졌답니다. 이제 SDRAM에다 어셈블리 명령어를 직접 넣어 보도록 하죠. 이것도 역시 스크립트를 이용해서 간편하게 만들어 보도록 하죠.

▶코드 arm_add_instruction.cmm
    B::
         data.assemble 0x30000000 mov r1,#0x1
         data.assemble 0x30000004 mov r2,#0x1
         data.assemble 0x30000008 add r0,r1,r2
         step
         step
         step
         ENDDO
 

스크립트를 실행했다면 mov 명령어①가 보이는데, 하드웨어 디버거 명령어 "Step"을 3번 하면 R0 레지스터②에 2라는 값이 들어 있는 것을 확인해 볼 수가 있답니다.


이러한 방식으로 다양한 명령어를 테스트 해 보면서 직접 눈으로 ARM core 레지스터의 동작 확인을 해 볼 수가 있답니다. C 언어로 다음과 같은 연산문을 있는데, 어셈블리 명령어로 만든다면 어떻게 하면 될까요?

     z = (a << 2) | (b & 15);
     MOV r0, r0, LSL #2 ;          ( a << 2)
     AND r1, r1, #15 ;               ( b & 15)
    ORR r2, r0, r1 ;                   (a << 2) | (b & 15);

하드웨어 디버거의 스크립트로 만들어서 테스트를 해 보죠.

▶코드 arm_orr_instruction.cmm
     data.assemble 0x30000000 mov r0, #0x10
     data.assemble 0x30000004 mov r1, #0x20
     data.assemble 0x30000008 mov r0, r0, LSL #2
     data.assemble 0x3000000C and r1, r1, #15
     data.assemble 0x30000010 orr r2, r0, r1
     repeat 5
     stepprint " r2 = " r(r2)              ; r2 = 0x40
     ENDDO
 

PSR에 해당되는 CPSR, SPSR 레지스터 같은 경우는 반드시 ARM 명령문만 가능하고, 명령어는 MRS, MSR 있답니다. CPSR에 있는 control bit들을 제어 해 보도록 하죠. ARM core는 디폴트 모드가 SVC이고, 인터럽트는 모두 Disable되어 있답니다. 그래서 CPSR은 0xD3①으로 되어 있죠. 0x30000000 주소의 mrs 명령어가 실행되는 CPSR에 있는 값을 읽어서 R0 레지스터②에 저장을 한답니다. 그리고 개발자가 바꾸고 싶은 cpsr 값③을 지정하고, msr 명령어가 실행④되면 CPSR은 0x10이라는 값⑤을 가지게 되며 USR 모드로 바뀌게 되는 거랍니다. 이 명령어는 주로 모드 전환이 필요할 때 많이 쓰이는 명령어랍니다.


THUMB 명령어
16 bit 명령어로 구성되어 있어요. ARM 명령어처럼 기본적인 data processing 명령어부터 다양한 명령어가 제공된답니다.

  Data Processing ADD, ADC, SUB, SBC, RSB, RSC, AND, ORR, BIC, MOV, MVN, CMP, CMN, TST, TEQ …
  Multiply MUL, MLA …
  Load / Store LDR, LDS, PUSH, POP, STR, …
  Branch B, BLX, BX

THUMB Instruction으로 컴파일 완료 후 바이너리의 사이즈는 ARM보다 약 65% 감소하기 때문에 메모리의 저장 공간을 적게 사용할 수가 있죠.


같은 소스코드이지만 ARM Instruction일 때는 4Byte(32bit) 단위로 명령어가 만들어지죠. 현재 ARM Instruction 개수는 14개이고, 4Byte이면 총 메모리 공간을 차지하는 size는 56KB랍니다. THUMB Instruction 같은 경우는 2Byte(16bit) 단위로 명령어가 만들어지기 때문에 THUMB Instruction 개수는 11개이고, 2Byte이면 총 메모리 공간을 차지하는 size는 22Byte랍니다.이런 결과라면 누구나 THUMB 명령어를 사용하는 게 유리하지 않을까요? 흔히 임베디드 제품은 단가가 낮을 수록 좋다고 하는데, 메모리 공간을 적게 차지하는 코드를 만들게 된다면 큰 메모리의 SDRAM 쓰지 않아도 되지 않을까요? ㅎㅎ 맞습니다. 맞고요. 그래서 주로 THUMB Instruction을 많이 사용하지요. 하지만 뭐든지 장점이 있으면 단점이 있는 법이죠. 세상만사 다 그렇듯 여기에도 존재한답니다. 단점들을 나열해 볼게요.

1. 분기 명령어를 제외하고는 조건부 실행이 안됩니다.
2. 레지스터 사용이 R0~R7으로 제안 됩니다.
3. Immediate 상수 값의 사용 범위가 제한적입니다.
4. Inline barrel shifter의 사용이 제안적입니다.
5. Exception 처리를 할 수 없습니다.

ARM 코어는 모든 Exception 처리를 ARM 명령어 상태에서 하도록 되어 있답니다. 즉, THUMB 명령어로 동작 중에 Exception 이 발생하면 무조건 ARM 명령어 상태로 바뀐다는 거죠. 6. CPSR과 SPSR를 바꿀 수가 없습니다. 즉, 인터럽트나 모드 비트[4:0] 전환을 할 수가 없답니다.7. MMU나 Cache 제어를 할 수가 없답니다. 주로 휴대폰 같은 시스템의 경우는 대부분 THUMB 코드가 많이 있답니다. 그렇다 보니 THUMB 명령어가 실행되다가도 Coprocessor 명령어와 같은 Instruction 실행이 필요하면 ARM 명령어 모드로 전환이 되고, 그 후 다시 THUMB 명령어가 실행되는 과정이 반복되지요. 이러한 상황을 ARM/THUMB 인터워킹(ARM&THUMB Interworking)이라고 부른답니다. 인터워킹 시 사용되는 BX라는 명령어와 ARM 아키텍처 V5T 이상에서 지원하는 BLX라는 명령어가 있답니다. 이 명령을 분석해 보시면 좀 더 이해가 쉽답니다.
  하드웨어 디버거를 통해 ARM1176JZF-S 프로세서에서 동작을 시켜 보도록 해 보죠. 0x00000000 주소에 mov 명령어가 있으면, 현재 Thumb ①명령어 상태이고 T bit가 "1"로 ② 된 상황이랍니다. 0x0 주소의 Mov 명령어가 실행되면 R0에는 0x10이라는 값이③ 들어가고, bx r0를 실행하면 r0의 주소④로 점프를 하는 것과 동시에 0x10이라는 값에서 제일 마지막 bit가 홀수이냐 짝수이냐에 따라 ARM/THUMB 명령어 상태로 바뀌게 된답니다. 0x10을 binary형태로 표현을 하면 "0001 0000" 이며, 마지막 비트가 "0" 이므로 ARM 명령어 ⑤상태로 바뀌게 되죠.


이제 새롭게 추가된 BLX 명령에 대해 알아보죠.두 명령어의 차이점은 링크 레지스터인 R14에 되돌아올 주소를 저장하냐의 차이랍니다. BX 명령어는 반드시 되돌아올 주소를 어딘가 명령문으로 만들어 줘야 하지만 BLX 명령어는 자동으로 되돌아올 주소를 백업한답니다. 그래서 0x00000002 주소의 blx 명령어가 실행되면, R14에는 0x2의 다음 주소인 (0x4)+1인 주소를 백업④을 하고, 0x10 주소로 점프를 한답니다.


Stack에 대한 ARM 명령어와 THUMB 명령어를 비교해 보도록 하죠.

     ARM 명령어    THUMB 명령어
   PUSH   STMFD R13!,{r1,r2,(R14) }    PUSH {r1,r2,r14}
   POP   LDMFD R13!,{r1,r2,(R15) }    POP {r1,r2,r15}

THUMB-2 명령어
ARMv7 이후부터 THUMB-2가 완벽히 지원이 되는데, Coretex-A8 프로세서라면 THUMB-2 명령어를 사용할 수가 있답니다. THUMB 명령어보다 향상된 THUMB-2 명령어가 있답니다. THUMB-2는 THUMB 16bit Instruction Set, ARM 32bit Instruction Subset, New 16/32 Instructions set 명령어가 있답니다. 그래서 ARM 명령어와 거의 비슷한 기능을 제공하고, 32bit와 16bit 명령어를 포함하여 성능은 ARM 명령어와 유사하지만 THUMB처럼 코드 사이즈가 매우 적게 만들어져 고밀도 코드를 만들어 낸답니다.


THUMB-2는 기존 THUMB 명령어와 함께 사용이 가능하며 ARM 명령어와 같은 기능도 구현 할 수가 있어서 컴파일 옵션에다 -mthumb 넣고 컴파일을 하면 ARM명령어와 THUMB 명령어가 섞여 만들어 진답니다.


 

마지막으로 기존의 THUMB은 조건부 실행을 할 수 없었지만 THUMB-2 명령어에서는 조건부 실행이 가능하도록 별도의 TI 명령어가 제공되어 일부 명령어는 조건에 따라 실행이 가능하답니다. 또한 THUMB-2를 지원하지 않는 ARM 코어의 경우에는 Exception이 발생하면 무조건 ARM 명령어 상태로 모드가 바뀌면서 Exception을 처리해야 했지만 THUMB-2에서는 THUMB 상태에서도 Exception 처리가 가능해 졌답니다. 그리고 코프로세서를 접근할 수 있는 명령어도 제공됩니다. 컴파일 하는 방법에 대해 알아보아요.우선 웹사이트에서 Cortex-A8를 지원하는 GCC 컴파일러를 구해서 설치 하시기 바랍니다. "arm-2010q1-188-arm-none-eabi.exe" 이름을 가진 파일을 구하고, 설치 하실 때 C:/GNUARM 이름으로 지정하시면 됩니다. 컴파일을 해 보도록 하죠

  CMD> c:\gnuarm\bin\arm-none-eabi-gcc -g -mcpu=cortex-a8 -mthumb -o             main.o main.c


하드웨어 디버거로 직접 명령어를 확인 해 보도록 하죠. THUMB-2로 컴파일을 했을 때 ARM 명령어와 THUMB 명령어①가 섞여 있는 것을 알 수가 있지요. 반면 -marm 옵션으로 컴파일을 하면 ARM명령어②만 만들어 진답니다.

Co-processor 명령어
ARM core에 레지스터가 있듯이 코프로세서에도 레지스터가 있는데, 각 레지스터 역할을 살펴보면 다음과 같아요. 특히 C15:1 같은 경우는 MMU나 Cache 을 Enable/Disable하는 역할을 하죠.

   C15.0

   ID code register Opcode_2 = 0 Cache type register
   Opcode_2 = 1

   C15.1

   Control register, Cache, MMU enable, Endian, Clock control

   C15.2    Translation table base register
   C15.3    Domain access control register
   C15.5    Fault status register
   C15.6    Fault address register
   C15.7    Cache operation register Cache control
   C15.8    TLB operation register
   C15.9    Cache lockdown register
   C15.10    TLB lockdown register
   C15.13    FSCE PID register Fast Context Switching Extension
   C15.14    Debug support register DCC enabled

코프로세서 관련 명령어는 두 가지가 있답니다.

MCR: Move CPU register to coprocessor register
MRC: Move from coprocessor register to CPU register

개발자는 이 명령어를 통해 어떤 일을 할 수 있는지 몇 가지만 나열해 보도록 하죠.\

  MMU_EnableICache:   mrc p15,0x0,r0,c1,c0,0x0
                                  mcr p15,0x0,r0,c1,c0,0x0
                                  mov pc,r14
  MMU_DisableICache:  mrc p15,0x0,r0,c1,c0,0x0
                                  bic r0,r0,#0x1000
                                  mcr p15,0x0,r0,c1,c0,0x0
                                  mov pc,r14
  MMU_EnableDCache:  mrc p15,0x0,r0,c1,c0,0x0
                                  orr r0,r0,#0x4
                                  mcr p15,0x0,r0,c1,c0,0x0
                                  mov pc,r14
  MMU_DisableDCache: mrc p15,0x0,r0,c1,c0,0x0
                                  bic r0,r0,#0x4
                                  mcr p15,0x0,r0,c1,c0,0x0
                                  mov pc,r14
 

R0는 ARM core 레지스터이고, C1은 코프로세서 1번을 뜻합니다. 그래서 ARM core R0 레지스터의 값을 C1레지스터로 쓰기 명령어를 하죠.


VFP 그리고 NEON 명령어
VFP(Vector Floating Point)는 부동 소수점 연산을 하는 단정도와 배정도 부동 소수점 연산을 제공해 주는 보조 연산장치랍니다. 부동 소수점 연산 명령어들이 별도로 존재하고 흔히 SIMD(Single Instruction Multiple Data)라고 불려집니다. ARM10 프로세서에서 처음으로 VFPv1 나왔으며, ARM11에는 VFPv2가 적용됐답니다. Cortex-A8는 VFPv3 적용됐고 이것을 NEON 이라고 불린답니다. NEON은 VFPv2보다 2배 이상의 성능을 내며 코드 효율이 좋아서 저전력 구현이 가능한 특징을 가지고 있답니다. 주로 3D그래픽, 오디오, 비디오, 이미지 그리고 음성 처리 등을 수행한답니다. NEON 아키텍처는 64bit 레지스터가 32개(D0~D31), 128bit 레지스터 16개(Q0~Q15)가 있답니다. 그래서 32bit 부동 소수점 연산 및 8bit, 16bit, 32bit 정수 연산 그리고 일부 64bit 연산을 지원한답니다. 정수 파이프라인(Integer pipeline)과는 별도의 실행 파이프라인(execution pipeline)이 있어서, 단수(Integer)와 단정도 플로팅-포인트(single precision floating-point)값을 모두 처리할 수 있고, 비정렬 데이터 엑세스(unaligned data accesses) 및 배열 형태로 저장된 데이타를 간편하게 로딩 지원을 한답니다.


정수 데이타 처리①하는 세 가지 파이프라인으로 구성과 NEON floating-point(NFP) 데이타 처리는 두 개의 더하기② 파이프라인과 곱하기③ 파이프 라인이 있지요. 단정도와 배정도 산술(single and double precision arithmetic)를 위한 VFPLite(vector floating-point)④가 있고, 정수 연산 데이타 전송을 담당하는 PERM⑤파이프라인이 있답니다. ARM 컴파일러는 컴파일 옵션 중에 ARM 명령어 또는 THUMB 명령어 옵션으로 선택할 수가 있도록 되어 있답니다. 하지만 SIMD 명령어는 ARM 명령어 형식으로만 지원했답니다. 즉, SIMD 명령어는 반드시 ARM 명령어 옵션으로 해야만 했었죠. 하지만 NEON는 Advanced SIMD 명령어가 지원 되면서부터 ARM/THUMB-2 모두 지원이 가능해졌답니다. SIMD 명령어로는 SADD, SSUB, QADD, QSUB, SHADD, SHSUB, SXT, SXTA, SSAT, SEL, PKH 등 제공되며, NEON의 Advanced SIMD 명령어는 VLDR, VSTR, VLDM, VSTM, VLD, VST, VMOV, VMRS, VDUP, VADD, VSUB 등 모두 "V~"로 시작되어 누구나 쉽게 구별할 수 있으며, 모두 NEON 전용 레지스터가 처리를 한답니다.

VFPv2인 ARM1176JZF의 VFP 레지스터 랍니다.


하드웨어 디버거로 전체 레지스터를 확인 해 보도록 할게요.


VFPv3인 Cortex-A8의 NEON 레지스터 랍니다.


하드웨어 디버거로 전체 레지스터를 확인 해 보도록 할게요.


기타 레지스터의 역할은 다음과 같아요.FPSCR(Floating-Point System ID Register): 읽기 전용으로 특권 모드에서만 접근이 가능하고, VFP와 NEON의 버전을 확인할 수 있는 레지스터랍니다. FPEXC(Floating-Point Exception Register): NEON 및 VFP 활성화를 해 주는 레지스터랍니다. FPSID(Floating-Point Status and Control Register): 특권과 비특권모드에서 모두 접근이 가능하고, LEN과 STRIDE 비트는 벡터의 길이와 벡터의 처리 방식을 지원한답니다.
그럼 간단한 예제 프로그램을 만들어 직접 확인해 보죠.웹사이트에서 Cortex-A8를 지원하는 GCC 컴파일러(arm-2010q1-188-arm-none-eabi.exe)를 구하고, 설치를 하실 때 C:/GNUARM 이름으로 설치하시면 됩니다. 그리고 makefile, linker.ld, startup.s 파일을 만들어 보죠.
makefile 만드실 때 가장 중요한 것은 NEON 옵션이랍니다. NEON 명령어를 지원하기 위한 옵션으로 "-mfloat-abi=softfp -mfpu=neon -ftree-vectorize -ftree-vectorizer-verbose=6" 넣어 주셔야 해요.

▶코드 makefile
   # Cortex-A8 GCC (Makefile)
   PROJECT = Cortex-A8
   VERSION = 4.4.1
   PRE = arm-none-eabi
   TOOLDIR = C:/GNUARM
   LIBCDIR = $(TOOLDIR)/$(PRE)/lib
   LIBGCCDIR = $(TOOLDIR)/lib/gcc/$(PRE)/$(VERSION)
   INCLUDE = -nostdinc -I. -I$(LIBGCCDIR)/include -I$(TOOLDIR)/$(PRE)/include
   AS = $(TOOLDIR)/bin/$(PRE)-as
   CC = $(TOOLDIR)/bin/$(PRE)-gcc
   LD = $(TOOLDIR)/bin/$(PRE)-ld
   ARMSIZE = $(TOOLDIR)/bin/$(PRE)-size
   SRC = $(wildcard *.c)
   ASRC = $(wildcard *.s)
   OBJS = $(SRC:.c=.o) $(ASRC:.s=.o)
   # FLAGS setting
   CFLAGS = $(INCLUDE) -g -gdwarf-2 -O0 -W -Wall -Wstrict-prototypes -Wno-trigraphs
  CFLAGS += -fno-strict-aliasing -fno-common -pipe
   CFLAGS += -mcpu=cortex-a8 -fno-builtin
   CFLAGS += -mfloat-abi=softfp -mfpu=neon -ftree-vectorize -ftree-vectorizer-verbose=6
  LDFLAGS = --cref -Bstatic -nostdlib -nostartfiles -p -EL -T linker.ld -Map $(PROJECT).map

  all: $(PROJECT).elf$(PROJECT).elf : $(OBJS) $(LD) $(LDFLAGS) -o $(PROJECT).elf $(OBJS)     -L$(LIBCDIR) -L$(LIBGCCDIR) -lc -lgcc -lc $(ARMSIZE) $(PROJECT).elf
   @echo -------------------------------------------------------
   @echo Finished !!! %.o : %.s $(CC) -c $(CFLAGS) -o $@ $< %.o : %.c
   $(CC) -c $(CFLAGS) -o $@ $<
   clean: rm -f $(OBJS)
             rm -f $(PROJECT)
             rm -f *.dmp
             rm -f $(PROJECT).map
             rm -f $(PROJECT).bin
 

▶코드 linker.ld
   OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
  OUTPUT_ARCH(arm)
  ENTRY(_start)
  -- Code Start Address --
  __TEXT_START__ = 0x00000000;
  -- Section Definitions --
  SECTIONS
  {
       -- first section is .text which is used for code --
       .text __TEXT_START__ :
       {
           __TEXT_START__ = .;
          *startup.o (.text)
          *(.text)
          __TEXT_END__ = .;
          . = ALIGN(4);
       } -- .rodata section which is used for read-only data (constants) --
       .rodata :
       {
          __RODATA_START__ = .;
          *(.rodata)
         *(.rodata.*)
        __RODATA_END__ = .;
       . = ALIGN(4);
       }
       -- .data section which is used for initialized data --
      .data :
      {
      __DATA_START__ = .;
      *(.data)
      *(.data.*)
      __DATA_END__ = .;
     . = ALIGN(4);
     }
     -- .bss section which is used for uninitialized data --
     .bss :
     {
       __BSS_START__ = .;
       *(.bss)
       *(.bss.*)
      __BSS_END__ = .;
      . = ALIGN(4);
     }
     _end = .;
     __end = _end;
    PROVIDE(end = .);
   }

이 프로그램은 0x100~114까지 0x11112222~0xBBBBCCCC 데이타가 들어가고, NEON 레지스터 D0~D2까지 로딩을 한답니다.

▶코드 startup.s
   BASE_ADDR0 = 0x100
   BASE_ADDR1 = 0x104
   BASE_ADDR2 = 0x108
   BASE_ADDR3 = 0x10c
   BASE_ADDR4 = 0x110
   BASE_ADDR5 = 0x114
   .text
   .globl _start
   .extern main
  @ Main Routine
  _start:
   b ResetHandler
   b . @ handlerUndef
   b . @ SWI interrupt handler
   b . @ handlerPAbort
   b . @ handlerDAbort
   b . @ handlerReserved
   b . @ handlerIRQ
   b . @ handlerFIQ
  ResetHandler:
   ldr r0, =BASE_ADDR5
   ldr r1, =0xCCCCBBBB
   str r1,[r0]
   ldr r0, =BASE_ADDR4
   ldr r1, =0xAAAA9999
   str r1,[r0]
   ldr r0, =BASE_ADDR3
   ldr r1, =0x88887777
   str r1,[r0]
   ldr r0, =BASE_ADDR2
   ldr r1, =0x66665555
   str r1,[r0]
   ldr r0, =BASE_ADDR1
   ldr r1, =0x44443333
   str r1,[r0]
   ldr r0, =BASE_ADDR0
   ldr r1, =0x22221111
   str r1,[r0] vld3.16 {d0, d1, d2}, [r0] bl main b . .end
 

컴파일을 해 보죠.

   CMD> make
  -------------------------------------------------------
  C:/GNUARM/bin/arm-none-eabi-size Cortex-A8.elf
   text data bss dec hex filename
   168 0 4 172 ac Cortex-A8.elf
  -------------------------------------------------------
   Finished !!!
 

이제 눈으로 직접 확인해 보기 위해서 하드웨어 디버거로 사용해 보아요.


ARM/THUMB 명령어 - "500" PSR - "501"

 

by 히언 | 2012/04/15 21:34 | SOTO Story | 트랙백 | 핑백(1)

Linked at 친절한 임베디드 시스템 개발자.. at 2012/04/15 21:45

... 게 반했다? 503 파이프 라인(Pipe Line)의 법칙? 503 우리는 패밀리 505 엘시디(LCD) 드라이버 어떻게 만들죠? 506 그림 뷰어 어플 ... more

◀ 이전 페이지          다음 페이지 ▶