ARM 과 관련된 문서 ARM Architecture 가 있음에도 불구하고 ARM 아키텍처와 관련하여 따로 페이지를 만든 이유는 그만큼 중요하기 때문이다.
제대로 이해하지 않고 대충 넘어간 내용은 언젠가 뒤통수(?)를 치게 되어있다. 나의 경우에 CP15 가 그러했다. 졸업 프로젝트 - 문제점 정리 를 보기 바란다.
이를 계기로 코드를 이해하지 않고, 마구잡이로 copy & paste 하는 것은 재앙을 가져온다는 것을 깨달았다.
ARM 프로세서 데이터시트의 가장 마지막 부분의 몇 장 안되는 분량으로 설명되어 있는 CP15 는 아주 아주 중요하다. 그럼에도 불구하고, 시중에 나와 있는 ARM 관련한 서적 중에 CP15 에 대해서 자세하게 설명되어 있는 책들은 거의 없다.
그 중에 자세히 나온 책이 바로 'ARM 으로 배우는 임베디드 시스템' 이다. 여기서 언급하는 내용은 이 책의 8 장에 나온 내용을 발췌한 것이다.

ARM 프로세서의 제어

ARM 프로세서의 캐시, MMU, MPU, TCM, 쓰기 버퍼는 CP15, 즉 코프로세서 15 번 인터페이스를 이용하여 제어한다고 이미 설명한바 있다. 따라서 CP15 에는 캐시, MMU, MPU, TCM, 쓰기 버퍼를 제어하기 위하여 많은 제어용 레지스터를 가지고 있으며, 이 레지스터에 값을 기록하여 제어하고 읽어서 동작을 확인할 수 있다. ARM 프로세서에서 CP15 레지스터를 액세스할 때는 코프로세서 레지스터 전송 명령인 MCR 과 MRC 를 사용한다.

CP15 에 엑세스하는 방법은 다음과 같다.

MCR{<cond>} p15, 0, Rd, CRn, CRm, <opc_2>
MRC{<cond>} p15, 0, Rd, CRn, CRm, <opc_2>
  1. MCR : ARM 범용 레지스터 값을 코프로세서의 레지스터로 전송한다.
  2. MRC : 코프로세서의 레지스터 내용을 ARM 의 범용 레지스터로 전송한다.
  3. {cond} : 조건부 실행을 위한 조건을 나타낸다.
  4. p15 : 코프로세서 15 번 임을 나타낸다.
  5. <opc_1> 은 항상 0 이다.
  6. Rd 는 ARM 레지스터로 소스 또는 대상을 나타낸다(R0-R15).
  7. CRn : 기본 CP15 레지스터 번호를 나타낸다.
  8. CRm : 부가적으로 사용되는 CP15 레지스터를 나타낸다.
  9. <opc_2> : 부가적인 정보를 표시한다.

CP15 의 레지스터 CRn, CRm 의 종류와 사용법은 프로세서의 종류 별로 다르다. 따라서 개발에 사용되는 프로세서의 정보를 먼저 확인하여 CP15 레지스터의 종류와 사용법을 알아야 한다.

ARM920T 는 ARM9TDMI 코어에 캐시, MMU 및 쓰기 버퍼를 가지고 있는 프로세서이며, ARM920T 의 CP15 의 기본 레지스터 CRn 은 다음과 같다.

<표 8-1> ARM920T 의 CP15 레지스터

CRn 용도 비고
0 ID 코드 <opc_2> = 0
캐시 타입 <opc_2> = 1
1 제어용 레지스터 MMU, 캐시 사용여부 제어 등
2 변환 테이블 위치 주소
3 도메인 접근제어 16 개의 도메인 제어
4 Reserved
5 FAULT 상태
6 FAULT 발생 위치 주소
7 캐시 동작 제어
8 TLB 동작 제어
9 캐시 락다운
10 TLB 락다운
11 Reserved
12 Reserved
13 FSCE PID Fast contect switching Extension
14 Reserved
15 테스트용

위의 표를 보면 0 번 레지스터는 ID 코드 또는 캐시 타입을 나타내고 있다. 이 레지스터에서 값을 읽었을 때 어떤 값을 표현하는지는 읽을 때 사용되는 MRC 명령의 <opc_2> 에 의해서 결정된다. ID 코드를 읽을 때는 아래와 같이 MRC 명령을 사용하여 읽을 수 있고, ID 코드 레지스터는 <표 8-2> 와 같은 정보를 가진다.

MRC p15, 0, r0, c0, c0, 0  // ID 코드를 읽어 r0 에 읽어온다

<표 8-2> CP15 레지스터 0 의 ID 코드 정보

비트 기능 값(value)
31:24 제작자 0x41
23:20 사양 버전 0x1
19:16 아키텍처 버전 0x2(v4T)
15:4 프로세서 이름 0x920(ARM920)
3:0 레이아웃 버전 0x0

캐시 타입을 읽을 때는 아래와 같이 MRC 명령을 사용하여 읽을 수 있다. 하지만 ID 코드를 읽을 때와는 달리 <opc_2> 값은 1 을 사용해서 읽어야 한다.

MRC p15, 0, r0, c0, 1   // 캐시 타입 정보를 읽어 r0 에 읽어 온다

ARM920T 의 경우 캐시 타입 레지스터에 대한 정보를 살펴보면 [표 8-3] 과 같다.

비트 기능 값(value)
31:29 Reserved 000
28:25 캐시 타입 0110
24 Harvard 캐시 또는 Unified 캐시 1(Harvard 캐시)
23:21 Reserved 000
20:18 데이터 캐시 사이즈 정보 101(16KB)
17:15 데이터 캐시 Associate 방식 110(64 way 방식)
14 Reserved 0
13:12 데이터 캐시의 라인 당 워드 수 10(8 워드)
11:9 Reserved
8:6 명령어 캐시 사이즈 정보 101(16KB)
5:3 명령어 캐시 Associate 방식 110(64 way 방식)
2 Reserved
1:0 명령어 캐시의 라인 당 워드 수 10(8 워드)

CP15 의 레지스터 1 번은 제어용으로 사용되며, 각 비트는 아래 <표 8-4> 와 같은 정보를 가지고 있다.

<표 8-4> CP15 레지스터 1, 제어용 레지스터 정보

비트 기능 정보
0 MMU 활성화
1 Alignment 오류 활성화 정렬되지 않은 메모리 접근에 대한 오류 발생
2 데이터 캐시 활성화
6:3 Reserved
7 빅 엔디안 빅 엔디안과 리틀 엔디안 정보
8 시스템 보호 비트 'S' 액세스 제어 비트
9 ROM 보호 비트 'R' 액세스 제어 비트
11:10 reserved
12 명령어 캐시 활성화
13 벡터 위치 변경 벡터 위치를 0xffff0000 으로 변경
14 라운드 로빈 반환 캐시의 반환 방식 선택
29:15 Reserved
30 FastBus select 버스 사용 방식 설정
31 Asynchronous clock select 시스템 버스의 클럭 설정

제어용 레지스터는 아래와 같이 읽고 쓸 수 있다.

MRC p15, 0, r0, c1, c0, 0   // 제어 정보를 읽어 r0 에 읽어 온다
MCR p15, 0, r0, c1, c0, 0   // r0 값을 제어 레지스터에 저장한다

일반적으로 제어용 레지스터에 정보를 설정할 때는 새롭게 모든 정보를 설정할 수도 있지만 기본의 값을 읽어서 원하는 부분만 수정한 다음 저장하는 방식을 많이 사용한다.
간단한 예로 MMU 를 활성화하는 프로그램을 작성해보면 아래와 같이 프로그램이 작성된다.

MRC p15, 0, r0, c1, c0, 0  // 제어 정보를 읽어 r0 에 읽어 온다
ORR r0, r0, #1     // MMU 인에이블 비트 0 을 1 로 한다
MCR p15, 0, r0, c1, c0, 0  // r0 값을 제어 레지스터에 저장한다

MMU 는 가상 주소를 물리 주소로 바꾸고, 각각의 메모리 공간에 대한 접근 권한, 캐시 사용 여부를 지정하기 위하여 변환 테이블을 필요로 한다. CP15 의 레지스터 2 는 MMU 변환 테이블이 저장되어 있는 물리 메모리 공간의 주소를 저장하는 레지스터이고, 이 레지스터의 비트 <31:14> 에 변환 테이블의 주소 정보가 저장된다.
TTB 레지스터는 다음과 같이 액세스된다.

MRC p15, 0, r0, c2, c0, 0    // TTB 를 읽어 r0 에 읽어 온다
MCR p15, 0, r0, c2, c0, 0    // r0 값을 TTB 레지스터에 저장한다

도메인은 접근권한을 쉽고 빠르게 관리할 수 있는 방법을 제공한다. 도메인 액세스를 제어하기 위한 코프로세서 레지스터는 다음과 같이 액세스 된다.

MRC p15, 0, r0, c3, c0, 0    // 도메인 정보를 읽어 r0 에 읽어 온다
MCR p15, 0, r0, c3, c0, 0    // r0 값을 DACR 에 저장한다. 

FSR 레지스터는 최종으로 발생한 도메인 접근 오류 및 메모리 오류에 대한 정보를 저장하고 있다.

<표 8-5> CP15 레지스터 4, FSR 정보

비트 설명
31:9 기록할 때는 0 이어야 한다
8 읽을 때 0, 기록할 때는 0 이어야 한다
7:4 오류가 발생한 도메인(D0-D5) 정보
3:0 FAULT 타입

메모리 오류는 명령어를 읽으면서 발생할 수도 있고, 데이터를 읽거나 쓰다가 발생할 수 있다. FSR 을 액세스할 때 <opc_2> 가 1 이면 명령어를 읽어오다가 발생한 오류 정보를 가지고, 0 이면 데이터를 액세스 하다가 발생한 오류 정보를 가진다.

MRC p15, 0, r0, c5, c0, 0   // 데이터 FSR 을 읽어 r0 에 읽어온다
MCR p15, 0, r0, c5, c0, 0   // r0 값을 데이터 FSR 에 저장한다
MRC p15, 0, r0, c5, c0, 1   // 명령어 FSR 을 읽어 r0 에 읽어온다
MCR p15, 0, r0, c5, c0, 1   // r0 값을 명령어 FSR 에 저장한다

FAR 레지스터는 최종으로 데이터를 액세스하다가 발생한 주소(Modified Virtual Address)를 저장하고 있는 레지스터다. 명령어를 읽으면서 발생하는 오류에 대해서는 발생한 오류의 주소 정보를 저장하지 않는다.
FAR 레지스터는 다음과 같이 접근한다.

MRC p15, 0, r0, c6, c0, 0  // 데이터 FAR 을 읽어 r0 에 읽어온다
MCR p15, 0, r0, c6, c0, 0  // r0 값을 데이터 FAR 에 저장한다

이 레지스터는 쓰기 전용 레지스터로 명령어 캐시와 데이터 캐시를 제어하기 위한 레지스터이다. 캐시 동작을 CRm 과 <opc_2> 정보를 이용하여 <표 8-6> 과 같이 제어된다.
이때 사용되는 데이터는 ARM 의 범용 레지스터에 기록되는 값을 의미한다.

<표 8-6> CP15 레지스터 7 과 캐시 동작 제어

기능 데이터 사용되는 명령
ICache 와 DCache 를 무효화 모두 0 MCR p15, 0, r0, c7, c7, 0
ICache 무효화 모두 0 MCR p15, 0, r0, c7, c5, 0
ICache 의 단일 주소 무효화 MVA 주소 사용 MCR p15, 0, r0, c7, c5, 1
Prefetch ICache line MVA 주소 사용 MCR p15, 0, r0, c7, c13, 1
DCache 무효화 모두 0 MCR p15, 0, r0, c7, c6, 0
DCache 의 단일 주소 무효화 MVA 주소 사용 MCR p15, 0, r0, c7, c6, 1
Drain write Buffer 모두 0 MCR p15, 0, r0, c7, c10, 4
인터럽트 대기 모두 0 MCR p15, 0, r0, c7, c0, 4

TLB 는 MMU 의 변환 테이블을 관리하기 위하여 사용하는 캐시와 유사한 구조의 메모리이다. TLB 는 아래의 <표 8-7> 과 같이 제어된다.

<표 8-7> CP15 레지스터 8 과 TLB 동작 제어

기능 데이터 사용되는 명령
TLB 를 무효화 모두 0 MCR p15, 0, r0, c8, c7, 0
I TLB 무효화 모두 0 MCR p15, 0, r0, c8, c5, 0
I TLB 의 단일 주소 무효화 MVA 주소 사용 MCR p15, 0, r0, c8, c5, 1
D TLB 무효화 모두 0 MCR p15, 0, r0, c8, c6, 0
D TLB 의 단일 주소 무효화 MVA 주소 사용 MCR p15, 0, r0, c8, c6, 1

<표 8-7> 에서 I TLB 는 명령어 MMU 용 TLB 를 나타내고, D TLB 는 데이터 MMU 용 TLB 를 나타낸다.

캐시 락다운은 캐시에 저장된 일정한 명령이나 데이터를 갱신하지 않고 항상 캐시에 존재하도록 하여 일정한 성능을 보장하는 방법이다.
캐시 락다운은 빅팀 카운터를 제어하여 이루어진다. ARM920T 의 경우 빅팀 카운터는 캐시라인에 따라 0 에서 63 까지 사용된다. 또한 캐시 락다운 레지스터를 액세스 할 때 <opc_2> 가 0 이면 데이터 캐시를, 1 이면 명령어 캐시에 대한 락다운을 제어한다.

<표 8-8> CP15 레지스터 9 와 캐시 락다운 제어

기능 데이터 사용되는 명령
DCache 의 락다운 베이스를 읽는다 Base MRC p15, 0, r0, c9, c0, 0
DCache 의 빅팀 과 락다운 베이스를 쓴다 Victim = Base MCR p15, 0, r0, c9, c0, 0
ICache 의 락다운 베이스를 읽는다 Base MRC p15, 0, r0, c9, c0, 1
ICache 의 빅팀과 락다운 베이스를 쓴다 Victim = Base MCR p15, 0, r0, c9, c0, 1
D TLB 의 단일 주소를 무효화 한다 MVA 주소 사용 MCR p15, 0, r0, c8, c6, 1

예를 들어, 특정 영역의 데이터를 데이터 캐시의 라인 0 에 로드하고 캐시를 락다운하는 방법은 다음과 같다.

MOV r0, #0
MCR p15, 0, r0, c9, c0, 0   // r0, 즉 victim 0 을 레지스터 9 에 쓴다
LDR r1, [r2]    //  데이터를 읽어 캐시에 로드한다. 이때 r2 에는 락다운할 메모리의 주소가 있으며, 이 주소에서 라인 크기만큼 캐시의 라인 0 에 로드된다
MOV r0, #1
MCR p15, 0, r0, c9, c0, 0    // r0, 즉 victim 1 을 레지스터 9 에 쓴다. 

위 동작에 의해서 로드된 데이터는 항상 캐시에 존재하게 되면 새롭게 캐시에 로드되는 경우 빅팀 카운터는 0 번 라인을 제외한 1 에서 63 번 라인에만 갱신한다.

TLB 락다운은 역시 TLB 의 특정 영역이 갱신되지 않도록 하는 방식으로 캐시 락다운과 유사한 방식으로 제어된다.
아래의 <표 8-9> 는 TLB 락다운 제어 방법을 보여준다.

<표 8-9> CP15 레지스터 10 과 TLB 락다운 제어

기능 데이터 사용되는 명령
D TLB 의 락다운을 읽는다 TLB 락다운 MRC p15, 0, r0, c10, c0, 0
D TLB 의 락다운을 읽는다 TLB 락다운 MCR p15, 0, r0, c10, c0, 0
I TLB 의 락다운을 읽는다 TLB 락다운 MRC p15, 0, r0, c10, c0, 1
I TLB 의 락다운을 읽는다 TLB 락다운 MCR p15, 0, r0, c10, c0, 1

프로세스 ID(PID) 레지스터는 빠르게 문맥교환을 하기 위해서 사용하는 레지스터로 프로세서 코어에서 구동되는 0 에서 32MB 까지의 주소 정보를 새로운 주소로 매핑하는 용도로 사용된다. 이 레지스터에는 비트 <31:25> 에 변환 정보가 저장되어 총 64 개까지 매핑할 수 있다. 아래의 <그림 8-2> 는 CP15 의 레지스터 13 번을 이용하여 주소 변환 과정을 보여준다.

프로세스 ID 레지스터는 아래 명령에 의해서 액세스 된다.

MRC p15, 0, r0, c13, c0, 0    // 프로세스 ID 를 읽어 r0 에 읽어온다
MCR p15, 0, r0, c10, c0, 0    // r0 값을 프로세스 ID 레지스터에 저장한다

Xscale 은 인텔의 ARM 구조 v5TE ISA 로 설계된 마이크로 아키텍처로, 캐시, MMU 및 쓰기 버퍼를 가지고 있다.
Xscale 의 CP15 기본 레지스터 CRn 은 다음 <표 8-12> 와 같다.

<표 8-12> Xscale 의 CP15 레지스터

CPn 용도 비고
0 ID 코드 <opc_2> = 0
캐시 타입 <opc_2> = 1
1 제어용 레지스터 MMU, 캐시 사용여부 제어등
2 변환 테이블 위치 주소
3 도메인 접근 제어 16 개의 도메인 제어
4 Reserved
5 FAULT 상태
6 FAULT 발생 위치 주소
7 캐시 동작 제어
8 TLB 동작 제어
9 읽기 버퍼 제어
10 TLB 락다운
11 Reserved
12 Reserved
13 FSCE PID Fast contect switching Extension
14 디버그용
15 테스트 및 클럭 제어용
  • computer/rtcclab/arm_이해하기_-_cp15.txt
  • Last modified: 3 years ago
  • by likewind