※ 용어 정의 Rd: Destination Register / Rn: Operand1 Register / Rm: Operand2 Register <cond>: Execution Condition code <S>: S-Suffix - Status Update Suffix - SPSR의 값을 CPSR로 불러와서 Status를 Update <!> : ! - Suffix - Writeback Suffix - [,]내의 선처리 연산 수행 후 값을 갱신 <Operand2>: Operand2가 가질 수 있는 형식 ㄱ. #Immediate: 32bit 명령에서 Immediate값은 8-bit pattern의 짝수 shift 값 만을 허용 ㄴ. Rm{, shift연산 #immediate}: Register(Rm)값에 #immediate 값으로 Shift 연산 |
- asr(Arithmetic Shift Right): Immediate의 값 만큼 right shift, 앞에 bit는 Sign Extension
- lsr(Logical Shift Right): Immediate의 값 만큼 right shift, 앞에 bit는 0으로 채움
- lsl(Logical Shift Left): Immediate의 값 만큼 left shift, 뒤에 bit는 0으로 채움
- ror(ROtate Right): Immediate의 값 만큼 rotate right, rotate후 bit 0값은 carry에 저장
- rrx(Rotate Right eXtend): rrx는 1bit 씩 rotate right, bit 0값은 carry에 저장
1. 데이터 처리 명령(General Data Processing Instruction)
add: Rd := Rn + <Operand2>
sub: Rd := Rn - <Operand2>
adc(ADd with Carry), sbc(SuBtract with Carry): Carry를 포함한 add, sub 연산
rsb(Reverse SuBtract): Rd := <Operand2> - Rn
rsc(Reverse Subract with Carry): Carry를 포함한 역 sub 연산
1.2 논리 연산
and: Rd := Rn & <Operand2>
orr: Rd := Rn | <Operand2>
eor: Rd := Rn ^ <Operand2>
bic: Rd := Rn & !<Operand2>
mov: Rd := <Operand2>
mvn: Rd := !<Operand2>
1.4 비교
cmp: Rn값에서 Opeand2값을 빼서 그 결과를 Status flag에 반영, SUBS와 동일한 명령
cmn: Rn값에서 Operand2값을 더해서 그 결과를 Status flag에 반영, ADDS와 동일한 명령
tst: Rn과 Opearand2를 bit and 연산을 수행해서 그 결과를 Status flag에 반영, ANDS와 동일한 명령
teq: Rn과 Operand2를 bit xor 연산을 수행해서 그 결과를 Status flag에 반영, EORS와 동일한 명령
2. 메모리 접근 명령(Memory Accesss Instruction)
Syntax: ldr<cond><B> Rd, label
ldr<cond><B><T> Rd, [Rn]
ldr<cond><B> Rd, [Rn, FlexOffset]<!> ;Pre-Indexed<Auto-Indexing>
ldr<cond><B><T> Rd, [Rn], FlexOffset ;Post-Indexed
<B>: B Suffix가 있을 경우 8-bit Unsigned byte 단위로 Access, 없을 경우 32-bit word로 Access
<T>: T suffix가 있을 경우 Processor가 User mode에서 memory access 처리
FlexOffset:
ㄱ.#Immediate: -4095 부터 -4096사이의 상수 값
ㄴ.{-}Rm{, shift연산}: Rm은 음의 부호를 가질 수 있으며, Rm의 Shift 연산도 가능함
2.1 Load 또는 Store 명령 예제
ldr r0, [r1]: r1에 저장된 주소를 이용해서 메모리로부터 r0로 값을 불러옴
str r0, [r1], #4: r0의 값을 메모리의 r1의 주소에 저장하고 r1을 +4함.
참고) 부호가 있는 Halfword, Byte로 읽을 때는 SH(Signed Halfword), SB(Signed Byte) <--(ldr only)
Unsigned Halfword로 읽거나 저장할 때는 H를 사용.
Doubleword의 경우 D 를 사용, 이 때의 Offset은 {-}Rm 만 허용함.
2.2 Multiple Load 또는 Store 명령
<addrmode>: address mode에는 총 8가지가 있으며, 4가지는 address의 연상 방식에 따른
구분이며 4가지는 stack의 특성에 따른 구분이다.
- IA(Increment Address after each transfer), - IB(Increment Address after each transfer)
- DA(Decrement Address after each transfer), - DB(Decrement Address after each transfer)
- FD(Full descending stack): stack의 주소에 data가 저장이 된 상태이고, 주소가 감소하면서 저장
- ED(Emtpy descending stack): stack의 주소에 data가 없는 상태이고, 주소가 감소하면서 저장
- FA(Full ascending stack): stack의 주소에 data가 저장이 된 상태이고, 주소가 증가하면서 저장
- EA(Emtpy ascending stack): stack의 주소에 data가 없는 상태이고, 주소가 증가하면서 저장
<!>: ! - Suffix가 있을 경우 마지막 주소(최종으로 이동한 주소)를 Rn에 저장함
<^>: SPSR의 값을 CPSR에 넣어줌, S-Suffix와 동일한 기능을 수행함.
ldm: Rn으로 부터 reglist에 지정한 register 수 만큼 값을 불러옴
stm: reglist에 있는 register의 값들을 Rn에 저장함.
[주의] Reglist에 지정한 Register의 순서와 상관없이 Register의 번호가 낮은 값이
메모리의 낮은 주소에 저장 또는 읽어진다. reglist는 'r1,r2,r3' 또는 'r1-r3'으로 표현
[자주 사용되는 형식] STMFD sp!, {r4-r7,lr} / LDMFD sp!, {r4-r7,pc}
3. 분기 명령(Branch Instruction)
Syntax: b<cond> label
b: label이 있는 주소로 branch(PC값에 label의 주소를 입력)
bl: 다음 명령의 주소를 lr에 저장하고, b와 같이 label의 주소로 branch
4. 기타 명령어
4.1 Software Interrupt
swi: 지정한 번호를 갖는 Software Interrupt를 발생시킴, 해당 번호에 맞는 SWI vector로 branch
(Software Interrupt가 걸리면 프로세서의 모드는 Supervisor로 변경됨)
4.2 PSR Access
psr에 지정한 값(cpsr 또는 spsr)로 부터 값을 불러와서 Rd에 저장 (Register <- PSR)
msr<cond> psr_fields, Rm
Register(Rm)의 값 또는 8bit Immediate값을 psr(cpsr 또는 spsr)에 저장 (Register -> PSR)
(field): f, s, x, c 값이 선택적으로 올 수 있음. 지정한 field 영역에만 값을 저장함.
[자주 사용되는 형식] msr CPSR_c,r0
N: 연산 결과가 음의 값을 가질 때 Set '1'
Z: 연산 결과가 영일 때 Set '1'
C: 연산 결과가 캐리(Carry)를 가질 때 Set '1'
V: 연산 결과 오버플로우(Overflow)를 발생시킬 때 Se
<ARM Instructioin Set>
① opcode<cond><S> Rd, Rn, #Immediate
② opcode<cond><S> Rd, Rn, Rm OP #Imm
③ opcode<cond><S> Rd, Rn, Rm OP Rs
- cmp, cmn 명령에서는 Rd는 무조건 '0' 값을 넣어줘야 함.(SBZ(Should Be Zero))
④ opcode<cond> Rd, Rn, #Immediate
⑤ opcode<cond> Rd, Rn, Rm OP #Imm
⑥ opcode<cond> Rd, <address>
⑦ opcode<cond><addrmode> Rm, Register_List^
⑧ opcode<cond><addrmode> Rm<!>, Register_List
⑨ opcode<cond><addrmode> Rm<!>, Register_List^
- P='1' Pre, P='0' Post / U='1' Increment, U='0' Decrement / B='1' Byte load, B='0' Word load /
W='1' Write-back(Auto-Index) W='0' / L='1' opcode는 ldr, L= '0' str /
I='1' Addr_mode가 모두 Offset field I='0' 앞에 Addr_mode는 '0' 뒤에 Addr_mode는 Rm /
S='1' Signed, S='0' Unsigned / H='1' Half Word, H='0' Word or Byte
⑩ b<cond> #Target Address(24bit Offset) - L의 값이 '1'이면 bl 명령
⑪ SWI #SWI Number
⑫ mrs<cond><S> Rd, PSR
⑬ msr<cond><S> PSR_<Field_Mask>, Rm
⑭ msr<cond><S> PSR_f, #Immediate
- S의 값이 '1'이면 SPSR에서, '0'이면 CPSR.
- SBO(Should Be One) 영역은 '1'로, SBZ(Should Be Zero) 영역은 '0'의 값을 넣어줘야 함
- ARM Developer Suite 1.2 Assembler Guide(ARM DUI 0068B):
http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/DUI0068.pdf
- ARM Asssembly Language Programming: http://www.arm.com/miscPDFs/9658.pdf
- kkamagui의 프로그래밍 작업실 ARM 어셈블리: http://kkamagui.springnote.com/pages/432792
- ARM Instruction Quick Finder: http://www.heyrick.co.uk/assembler/qfinder.html
- ARM Reference - rE Ejected: http://re-eject.gbadev.org/ =>ARM_Reference-rE.Ejected.pdf 자료 출처
"Embedded" 카테고리의 다른 글
- PCSpim - MIPS Simulator - 2009/09/22
- 'printf()' 함수 출력 옵션 - 2010/07/28
- ARM Assembly 명령어 정리 - 2010/01/20
- AVR과 CLCD를 이용한 디지털시계 - 2009/05/15
- AVR을 이용한 CLCD 출력 - 2009/04/27
- ARM Register 구성 및 mode - 2010/02/01
CODE16 1. 일단 Thumb mode compile되었군요.
PUSH {r0-r7,lr} 4. 어디선가 불리면서 r0~r6을 stack에 넣고, lr도 넣네요.
MOV r5,r0 6. 뭔지 모르겠지만 r0는 argument로 받았고
MOV r7,#2 8. r6에는 2를 넣습니다.
LSL r5,r5, r7 9. r5를 r7만큼 shift해서 r5에 넣고
ADD r4,r4,r5 10. r4에 다시 r4와 r5를 더한 것을 넣어요.
MOV r0,r4 11. r4을 r0에 넣고서
LDR r1,[r6,#4] ; data 12. r6가 가르키는 곳에서 4만큼 더한 곳의 값을 r1에..
BL manual 13. manual이라는 함수로 r0와 r1의 값을 가지고 jump
CMP r0,#0 14. manul의 return값이 0인지 확인해서
BNE |L1.10| 15. 0이 아니면 |L1.10|으로 jump
MOV r0,r4 16. 이제 돌아가기 위해서 r4를 r0에 넣고
POP {r3-r7,pc} 17. 이 함수를 부른 곳으로 돌아간다 .
DCW 0000
|L1.32| DATA
DCD data
ENDP
data
DCB 0x0000000a
DCB 0x00000014
DCB 0x0000001e
DCB 0x0000002
{
int sum=0; //아마도 r4
{
a = a^4; // 여기에서 재미있는 사실은 ^4할 때마다 <<2를 해주면 같은 효과
if (manual (sum,data[1])) // r4와 r6이 가르키는 이상한 data를 manual로 넘겨줌.
break; // 조건이 return이 0이 아니면 끝.
}
return sum; // r4를 return함.
}
1) Export i (== 전역변수)
-> 즉, i 라는 변수를 현재의 파일내에서 최초 선언하여 사용했지만,
다른 Object 파일에서 참조한다는 것을
assembler에게 알려주는 것.
2) IMPORT i (== extern int i;)
-> 현재의 소스파일에서 사용되는 변수 i는 다른 Object
파일에서 선언되어져 있다는 것을
Assembler 에게 알려주는 것입니다.
3) DCD == " = "
-> 즉 "table DCD 1,2,4 " 라고 되어진 것은 32bit 로 메모리를
3개 할당하고
각각에 1,2,4 라는 값을 초기값으로 넣고 그 시작 Address는 table 이라는 label 로 표현되어
집니다.
이것을 C로 표현하면 unsigned int table[3] = {1,2,4};
4) AREA == segment
-> 모든 프로그램은 크게 두가지의 기계어 영역을 반드시 포함하고
있습니다.
-> 실제로 실행하여야할 실행 코드를 포함하는 영역, 실행코드를 수행하기 위하여 사용되는
변수를
정의하여 R/W 하는데 사용해야할 영역, 전자는 CODE area 와 후자는 DATA area 를 말하는
것입니다.
--------------------------------------------아직 정리
안함-------------------------------------------------------
5)
ALIGN
-> ARM 은 기본적으로 모든 명령이 4byte 로 구성되어 집니다. 즉 4의 배수로 실행코드를 쪼개의 기계어를 하나하나
해석해 낸다고 보면 됩니다. 그런데 ASM 코드들 중간에 address 나 변수등을 정의할 때 1byte 나 2byte 로 정의를 해버리면 4의
배수가 않되는 경우가 발생합니다. 이때 오류가 발생할 수도 있습니다. 즉 4의 배수를 맞추기위하여 0으로 초기화되는 byte들을 추가로
패딩해주는 것이 필요한데 이것을 해주는 directive입니다.
6)SPACE
-> 초기값을 zero 로 지정한 바이트 만큼 메모리를 잡으라는 것입니다.
------------------------------------------------
EXPORT
INT_Loaded_Flag
INT_Loaded_Flag DCD 0
-> INT_Loaded_Flag 라는 변수를 0으로 잡는데 그 크기는 4bytes로 한다. 그리고 이 변수는 다른 파일에서
참조되어진다.
------------------------------------------------
IMPORT
INT_Initialize
INT_Resel_Addr DCD INT_Initialize
-> INT_Initialize 라는 이름의 함수 또는 변수가 현재의 파일이외에 다른 파일에 선언되어져 있는데 이것을 현재의 파일에서
참조하고 그 Address를 4bytes 크기로 끈어서 INT_Resel_Addr라는 변수명으로 재
정의한다.
------------------------------------------------
INT_IRQ_Vectors
DCD
INT_IRQ_Shell
-> INT_IRQ_Shell 이라는 함수의 시작 Address를 INT_IRQ_Vectors라는 사람이 인지할 수있는 label 로
재정의
한다.
-----------------------------------------------
INT_bss_start
DCD
|Image$$bss$$Base|
-> 이것은 "Image$$bss$$Base"의 의미를 알아야 합니다. Image$$bss$$Base은 ARM
assembler/linker 가 이해하는 label 입니다. 이것은 이미 무언의 약속으로 정의된 label 이므로 프로그래머가 어셈 코드에서
따러 정의하지 않아도 ARM asembler/compiler 가 알아서 생성해내는label 입니다. Image$$bss$$Base의 의미만
말하면 , bss 영역의 시작 address를 의미하는 것입니다.
즉, bss 영역의 시작 address를
INT_bss_start
라는 label로 재정의하여 프로그램을 용이하게 하겠다는 directive문구 입니다.
출처 : http://gauss.egloos.com/643866