Arm의 역사
Advanced Risk Machine 의 줄임말
Arm 프로세서 버전
Arm1, Arm2, Arm250, Arm2a, Arm610 등등 다양한 프로세서가 나옴. 동시에 ISA(Instruction Set Architecture) 버전 또한 업그레이드됨. 이 버전들을 관리하기 위해 Arm 계열, ISA 버전, Arm 코어를 구분하여 나누고 있다.
우리가 주의해야 할 건 ISA 버전이다. ISA 버전에 따라 바이너리의 명령어가 바뀌기 때문에 임베디드 기기 프로세서의 호환성을 맞추려면 해당 프로세서의 ISA 버전을 우선적으로 확인해야 한다.
Arm 아키텍처
Arm은 16비트, 32비트, 64비트를 지원한다. 이전까지 ISA 버전은 16비트, 32비트만 지원했지만 ARMv8-A 버전부터는 64비트도 지원한다.
32비트 arm은 AArch32, arm32라고 불리며 64비트 arm은 AArch64, arm64라고 불린다. 라즈베리파이 4도 ARMv8-A 버전을 사용하는 Cortex-A72 기반 프로세서를 사용하고 Apple의 M1 칩 또한 ARMv8-A 버전의 ISA를 사용하고 있다.
Arm / Thumb mode
Arm이 16비트를 지원하는 방식은 바로 mode를 나누는 것. Arm 프로세서에는 32비트의 Arm 모드, 16비트의 Thumb 모드가 있다. Arm 모드 명령어는 모두 4바이트이며 Thumb 모드 명령어는 2바이트이다. Arm 프로세서는 프로그램 실행 중 이 두 모드를 번갈아 사용할 수 있다.
Arm 프로세서의 모드 전환 기능은 주로 코드의 최적화를 위해 사용된다. 16비트 Thumb 모드를 사용하면 명령어 크기가 2바이트로 줄어들어서 메모리 공간을 더 효율적으로 사용할 수 있다. 메모리 크기가 제한된 임베디드에서 중요한 역할을 한다.
32비트 Arm 모드는 처리 성능이 더 높은 복잡한 계산을 필요로 하는 고성능 작업에 더 적합하다. 프로세서는 작업 종류에 따라 Arm 모드와 Thumb 모드를 동적으로 전환하며, 코드의 실행 효율과 메모리 사용량을 최적화하는 데 도움이 된다.
레지스터
Arm 레지스터는 r0~r12의 범용 레지스터와 r13~r15, Current Program Status Register(CPSR)의 특수 레지스터로 구성돼 있고 모두 4바이트이다.
이름 역할
| r0~r3 | 함수의 매개변수와 반환 값을 담는 레지스터, scratch 레지스터 |
| r4~r10 | 변수 레지스터 |
| r11 | Frame Pointer, x86-64에서의 rbp |
| r12 | Intra Procedural Call |
r0~r13 레지스터는 scratch/temporary 레지스터로 어떤 함수에서도 자유롭게 사용할 수 있다. 그러나 r4~r11는 callee-save 레지스터이며, 함수가 호출될 때 r4부터 r11의 데이터는 함수가 종료된 후에도 원래 상태를 유지해야 한다. 따라서 callee가 r4~r11까지 레지스터를 사용하려면, 데이터를 스택에 저장해두고 함수가 끝날 때 pop을 통해 데이터를 복구해야 한다.
특수 레지스터
이름 역할
| r13 (SP) | Stack Pointer, x86-64에서의 rsp |
| r14 (LR) | Link Register, return 주소 저장 |
| r15 (PC) | Program Counter, x86-64에서의 rip |
| CPSR | Current Program Status Register, 상태 레지스터 |
Thumb 모드의 경우에는 범용 레지스터로 r0~r7까지만 사용하고 Frame Pointer로 사용되던 r11을 r7로 대체하여 사용한다.
PC 레지스터의 경우 Arm의 Pipelining 특성 때문에 실제 실행되는 명령어의 두 줄 앞에 존재한다. fetch 되는 명령어가 PC에 있고 decode 되는 명령어의 경우 PC-4(Thumb 모드의 경우 PC-2), 실제로 execute되는 명령어는 PC-8(Thumb 모드의 경우 PC-4)에 있다.
CPSR 레지스터

31:28 비트는 Flag Field로 방금 처리된 연산 결과의 상태를 나타낸다. Flag로는 NZCV가 존재한다.
- Negative flag: 결과값이 음수일 때 1로 설정
- Zero flag: 결과값이 0일 때 1로 설정
- Carry flag: 덧셈에서 Carry 발생 시 1로 설정, 뺄셈에서 Borrow 발생 시 0으로 설정
- oVerflow flag: 덧셈/뺄셈에서 Signed Overflow가 발생 시 1로 설정
7:6 비트에 있는 field는 IRQ와 FIQ를 비활성화하는 비트로 1로 설정하면 해당 인터럽트가 비활성화된다. 바로 뒤에 있는 T bit는 Arm과 Thumb 모드를 나타낸다. 0은 Arm, 1은 Thumb 모드이다.
뒤에 4:0 비트는 현재 프로세서 모드를 나타낸다. User 모드를 제외한 6개의 모드는 Privileged 모드로 소스로 모드를 바꿀 수 있다.
M[4:0] Mode 역할
| 0b10000 | User | 애플리케이션이 동작하는 모드, CPSR에서 flag field만 수정 가능 |
| 0b10001 | Fast Interrupt Request (FIQ) | 높은(fast) 우선순위 인터럽트 발생 시 진입 |
| 0b10010 | Interrupt Request (IRQ) | 낮은 우선순위 인터럽트 발생 시 진입 |
| 0b10011 | Supervisor (SVC) | 시스템 콜(SVC) 발생 시 진입 |
| 0b10111 | Abort | 메모리 접근 실패 시 진입 |
| 0b11011 | Undefined | 정의 되지 않은 명령어 확인 시 진입 |
| 0b11111 | System | User 모드의 Privileged 버전, CPSR의 모든 비트 수정 가능 (User 모드와 레지스터 공유) |
Banked 레지스터
각 모드는 각자의 Register set을 가지고 있다. 예를 들어 User 모드에서 Abort 모드로 이동 시, 현재 r0~r12 레지스터를 스택에 저장하고 CPSR 레지스터는 Saved Program Status Register (SPSR) 레지스터에 저장한다. 이후 Abort 모드에서 User 모드로 이동할 때는 SPSR 데이터를 CPSR로 옮기고 스택에 저장한 User 모드의 레지스터를 가져온다.

각각의 모드는 banked register를 가지고 있다. 각 모드 별로 물리적으로 존재하며 banked register가 아닌 레지스터들은 User & System 모드의 레지스터를 공유한다. 공유하는 레지스터는 모드 변경 시 기존 모드의 레지스터 값을 스택에 넣어 현재 컨텍스트를 저장한다.