임베디드 레시피

Egloos | Log-in





캐시를 인에이블(Enable) 하려면?


뭘 알아야 이해를 하지

 캐시 사용하는 방법을 알아 보아요. 엠엠유와 마찬가지로 캐시를 사용하려면 코프로세서 레지스터를 이용해야 한답니다. 캐시는 인스트럭션 캐시③와 데이타 캐시④로 나누어 지고 암 코어와 인스트럭션 캐시 사이는 IVA, 데이타 캐시 사이에는 DVA가 존재한답니다. 그리고 각각 캐시와 엠엠유 사이에는 IMVA⑤와 DMVA⑥로 연결되어 있지요. 그리고 데이타 캐시 같은 경우에는 Write Buffer⑪와 Write back PA TAG RAM⑫이라는 것과 연결되어 있어요. 어떤 역할들을 하는지 알아 보죠.
 
 
 
캐시 메모리가 사용되는 큰 이유는 한번 실행한 프로그램은 재사용 율이 높다는 원칙에 의해 나왔죠. 최근에 사용된 데이타와 가까운 주소 내에 있는 데이타는 다시 사용될 가능성이 크다는 것입니다. 에스디램으로부터 캐시 메모리로 데이타 로딩 될 때, 그 주변의 데이타들까지 함께 로딩하는데 캐시 블록 단위 또는 캐시 라인 단위로 된답니다.
 하드웨어 디버거를 통해 코프로세서의 내용을 살펴보죠. ARM920T의 경우는 아래와 같아요.
 

 


ID Registers
  MIDR    41129200  IMPL  41  SPEC 01  ARCH 02  PARTNUM 0920  REV 00
  CTR     0D172172  CLASS 6      H   yes
                              DSIZE 16k   DASS 64   DM 0  DLENGTH 8
                              ISIZE  16k   IASS   64   IM 0   ILENGTH   8



 
MIDR은 Identity Code, CTR은 Cache Type 이며 Cache같은 경우 CTR 레지스터를 통해 확인해 볼 수 있지요. CTR 레지스터 중  H필드는 Harvard cache 인지 아닌지를 판단하며 DSIZE는 Data Cache size를 알 수가 있지요. 그리고 DASS는 way를 표현하는 거랍니다. way는 주소 매핑과 관련된 내용이랍니다.
캐시 메모리의 사이즈는 에스디램에 비해 매우 작은 편이며, 따라서 에스디램 처럼 동일한 주소 체계를 가질 수 없기 때문에 캐시 메모리만의 주소 매핑 방식이 따로 있지요. 직접 매핑(Direct mapping), 연상매핑(associative mapping), 집합  연상매핑(Set-associative mappoing) 이랍니다. 직접 매핑의 단점을 극복하기 위해 연상 매핑이 나왔으며, 연상 매핑의 단점을 보안하기 위해 집합 연상 매핑이 나왔다고 보시면 됩니다. 이중에서 집합 연상매핑이 가장 좋은 성능을 나타낸답니다.
 
ARM920T 같은 경우는 8워드(32 Bytes)이고 하바드 아키텍쳐, 캐시 사이즈는 I-Cache와 D-Cache 각각 16KB랍니다. 그리고 64 way(Cache Line/index)를 가지고 있답니다.
  
 

 
암 코어에 의해 요청한 데이타가 이미 캐시 메모리에 있다면 캐시 히트(hit)를 하고 캐시 메모리에 없다면 캐시 미스(miss)라고 하죠. 캐시 미스가 발생하면 에스디램 메모리로부터 일정한 블록 사이즈의 데이타를 가져와서 캐시 메모리에 저장한 후 그 데이타에서 특정 워드 크기의 데이타만 암 코어에 전달하게 된답니다.
 

 
캐시 히트면 큰 상관이 없지만 캐시 미스가 나면 에스디램에서 캐시 메모리로 다시 복사되어질 때 기존 캐시 메모리에서 희생 블록(victim block)을 결정을 해야 하죠. 그래서 희생 블록을 어떻게 결정할지에 대해 교체 알고리즘이 필요한데 라운드-로빈과 램덤 방식이 있답니다. 라운드-로빈 방식은 블록마다 별도의 카운터를 두고 블록 할당 시마다 1씩 증가 시키면서 다음 할당 블록을 결정하는 것이랍니다. 램덤 방식은 여러 블록 중에 무작위로 선택한답니다.
 
CR      00000000  iA   0         nF   0            RR  Random      V    0x00000000
                          I    Disable   R    Disable    S    Disable         B    Little
                          C  Disable   A     Disable    M    Disable
 
지금까지는 캐시 메모리에 있는 내용을 읽기 위주로 살펴 보았다면 이제는 쓰기 위주로 살펴보죠.
암 코어가 메모리에 대해 쓰기 작업을 요청하게 되면 캐시에 저장되어 있는 데이타를 변경해야 하고, 변경된 데이타는 언젠가는 에스디램에 쓰기를 해야 하죠. 그럼 언제 에스디램에 쓰기를 할까요?
쓰기의 경우 2가지의 방법으로 나눌 수가 있어요. Write-Through와 Write-Back랍니다.
Write-Through는 쓰기 요청을 하면 캐시 메모리의 데이타와 에스디램의 데이타를 같이 바꾸는 방식인데, 항상 에스디램에 쓰기를 하기 때문에 캐시 사용이 무의미 해지죠. 대신 Write-Through는 캐시 메모리의 데이타와 에스디램의 데이타가 항상 일치하기 때문에 캐시 클린(Clean) 작업이 필요하지 않답니다. Write-Back은 쓰기 요청시 캐시 메모리에만 쓰기 작업을 하고 그 변경 사실을 확인할 수 있는 표시(Dirty)를 표시한 후 캐시 메모리로부터 해당 블록의 데이타가 희생블록이 될 때 에스디램에 복사함으로써 캐시 메모리의 내용과 동일하게 유지하는 방식이랍니다. 예를 들면, 동일한 블록 내에 여러 번 쓰기를 할 경우 캐시 메모리에만 여러 번 쓰기를 하고 에스디램에는 한 번만 쓰게 한답니다. 아주 효과적으로 일을 하죠. 하지만 Write-Back 방식에서 캐시 플러시라든지 캐시 클린이라는 작업을 해야 하죠. 그렇지 않으면 데이타가 손실이 되는 일이 발생한답니다. 

 주로 D-Cache에만 해당 된다고 보시면 되는데 ⑪(WriteBuffer)과 ⑫(Write Back PA TAG Ram)이 D-Cache에만 연결되어 있다는 것을 볼 수가 있죠. WriteBuffer는 Write-Through 방식일 경우 에스디램에 데이타를 쓰기를 하는 역할을 해요. 암코어가 캐시 메모리에 데이타를 쓰는 시간은 얼마 안걸리지만 캐시 메모리에서 에스드램으로 쓰기를 하는 시간이 많이 들기 때문에, 이 시간을 줄이고자 WriteBuffer가 있답니다. Write Back PA TAG Ram는 Write-Back 방식일 경우 에스디램에 데이타를 쓰기 한답니다. 캐시 메모리에서 데이타 읽기와 쓰기에서 가장 중요한 것은 캐시 클린(Clean)과 캐시 플러시(Flush)랍니다.
 
캐시 클린은 더티 비트(Dirty bit)가 1로 set된 더티 캐시 라인의 데이타를 강제로 에스디램에 쓰기를 한다음 캐시 라인(00~1C까지)안에 있는 더티 비티를 '0'으로 초기화를 하는 거랍니다. 캐시를 클린하게 되면 캐시 메모리의 데이타와 에스디램 사이의 일관성을 유지한답니다. 주로 Write-Back 방식에서 사용되죠.
캐시 플러시는 Cache Line의 Dirty Bit를 0으로 reset 시키는 것이랍니다. 캐시 메모리에 있는 데이타가 유효하지 않다는 것을 알려 주죠. 캐시 플러시는 캐시 무효화(Cache Invalidate)를 수반한답니다. 암 코어에게 제어권을 훔쳐오는 DMA 같은 경우, 암 코어의 버스 제어권을 DMA가 훔쳐서 에스디램으로 바로 읽고, 쓰기를 합니다. 이 과정에서는 암 코어는 DMA가 어떤 데이타를 에스드램에서 읽고, 쓰기를 하는지 모르기 때문에 캐시 메모리에 있는 데이타와 불일치가 발생할 수가 있죠. 그래서 캐시 무효화가 필요하고 DMA에 의해서 몰래 변경된 데이타를 다시 캐시 메모리에 로드를 해야 합니다. 반대로 DMA가 다른 페리퍼럴로 쓰기를 할 때 캐시 메모리에 있는 데이타를 복사하는 것이 아니라 에스디램에 있는 데이타를 복사하기 때문에 캐시 메모리의 데이타와 에스디램의 데이타가 불일치를 돼서 엉뚱한 값이 DMA에 의해 전송되겠죠. 이 때가 바로 캐시 플러시가 필요할 때랍니다.
그리고 마지막으로 Valid 비트가 있는데, 캐시 블록의 데이타가 유효하다는 것을 알려 주는 비트죠. 만약 Valid 비트가 0으로 세팅이 되면 이후 해당 블록을 엑세스시 캐시 미스를 발생시킨답니다.

이제 프로그램으로 직접 제어를 해 보도록 해요.
캐시를 Enable을 하려면 코프로세서 레지스터 중 CR 레지스터(C1)를 사용한답니다.
실제 명령어는,


암 코어 R0 레지스터 값을 코프로세서 C1 레지스터에 Write를 한다는 의미이죠.
이 명령어가 실행됐을 때 하드웨어 디버거로 살펴보면 아래와 같고, I-Cache와 D-Cache 모두 Enable가 된답니다.
 

 
 
캐시도 마찬가지 인데요, Enable 한다고 해서 모든게 끝난게 아니랍니다. Enable을 하기 전에 반드시 해줘야 되는 3가지가 있답니다. 또한 캐시 명령어를 사용하기 위해서는 CP15.7번을 이용하면 된답니다.
 
첫 번째, 캐시 클린(Clean)입니다.

 


 

두 번째, 캐시 플러시(Flush)랍니다.
캐시의 읽기와 쓰기 동작에 모두 적용되기 때문에 중요하답니다.
mcr     p15,0x0,r0,c7,c5,0x0

세 번째, TLB의 무효화(InvalidateTLB)
mcr     p15,0x0,r0,c8,c7,0x0


씨 프로그램으로 만들어 보면 다음과 같아요.
 

 

코프로세서 “201”      엠엠유 “202” “308”  하드웨어 디버거 “207”      



 시즌1의 Cache, Cash? 를 먼저 보시고 연결해 보시면 더욱 이해하기 쉬운 연재가 되겠네요. ^^

by 히언 | 2010/07/18 23:27 | SOTO Story | 트랙백 | 핑백(1) | 덧글(6)

Linked at 친절한 임베디드 시스템 개발자.. at 2010/07/18 23:39

... p; 308 엠엠유(MMU)를 Enable 하려면? 309 캐시를 인에이블(Enable)하려면? 4장 RTOS 아나토미 400 마이크로 커널(Micro Kernel) vs 모놀리틱(Monolithic Kernel ... more

Commented by ruring at 2010/07/20 10:18
우어어려워 =-=;
누가 사진 도용하나요?
워터를 수놓으셨네욤 ㅎ
Commented by soto at 2010/07/21 13:47
네. 쉽게 쓰려고 했는데...
아직 제가 많이 미흡하네요. ^^;

워터는 트랜드라서...^^;
Commented by ruring at 2010/07/23 14:19
어려운단어에 겁먹어서 그렇죠뭐 ㅋ
다음주 목요일에 오실꺼죠~_~?
히언님이 쏘신데요 ㅋㅋㅋ
Commented by soto at 2010/07/24 09:02
정말요? 당근이죠~~~!!!
Commented by star at 2010/07/28 16:44
워터라...
당연한 조치라고 생각되어 지네요.
님의 소중한 자료니까요
Commented by soto at 2010/08/03 08:13
소중하다구요? ㅎㅎ
듣기 좋은 말이 군요..
감사~~!!
※ 이 포스트는 더 이상 덧글을 남길 수 없습니다.

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