一、基本概念
讲到这个cache呢,就要先讲一些其他东西来帮助我们理解它,首先要明白的是指令周期,什么是指令周期?
CPU的工作通常就是读取指令,然后执行指令,周而复始知道DOWN机,所以一个取指并且执行完指令的所需要的时间就被称为指令周期,在一个指令周期内,cpu必然会读取一次甚至多次指令,而CPU执行速度必然大于从内存读取指令的速度,所以CPU的能力受限于指令读取速度,为了解决这个问题,我们在内存与CPU中间加入了一种预读指令的机制,就是我们的cache高速缓存, 将指令从内存预读至缓存内,然后CPU又从高速缓存中读取指令,当然内存与缓存之间以块传送方式,而缓存与CPU之间采用字或字节传送,所以缓存与cpu之间通讯速度还是大于内存与缓存,为了平衡这个速度关系,通常CPU与内存之间会有多个缓存,比如s5pv210有L1和L2两个高速缓存。
当然扯点题外话,根据这种设计思路我们可以发现,CPU是不是类似于一个消费者,而内存是否类似于一个生产者,当生产者速度小于消费者的消费速度的时候,我们是不是就可以采用缓存在解决类似的问题?当然大多数时候,我们也是这样做的。
反之,如果消费者消费速度小于生产者呢?
这就意味着你可以将生产者的陈本再降低一些,就例如如果我有个女朋友,例如哈,当然我是没有的,程序猿怎么可能有女朋友嘛。如果我一分钟削一百个苹果,而我女朋友一分钟吃五十个苹果,那么我就生产过剩了,怎么办?通常换一把便宜点的撇点的刀来降低我的生产力就好了,对吧,妈的,我编不下去了,咦,怎么可以做到1分钟削一百个苹果呢,只要你有单身的手速,可以的。
二、实验
c代码,没错,仍然是点灯。
#define GPJ2CON (*(volatile unsigned long *) 0xE0200280)
#define GPJ2DAT (*(volatile unsigned long *) 0xE0200284)
void delay(unsigned long count)
{
volatile unsigned long i = count;
while (i--)
;
}
void led_blink()
{
GPJ2CON = 0x00001111;
while(1)
{
GPJ2DAT = 0; // LED on
delay(0x1000000);
GPJ2DAT = 0xf; // LED off
delay(0x1000000);
}
}
汇编代码
主要就是使能与关闭cache
.global _start
_start:
//关闭看门狗
ldr r0, =0xE2700000
mov r1, #0
str r1, [r0]
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0, r0, #0x00001000
#else
// set bit 12 (I) I-cache
orr r0, r0, #0x00001000
#endif
mcr p15, 0, r0, c1, c0, 0
ldr sp, =0xD0037D80
bl led_blink
halt:
b halt
这里有一段协处理器操作
bic r0, r0, #0x00001000 将第十三位清0,可看成与
orr r0, r0, #0x00001000 设置第十三位,可看成或
mcr p15 0 r0 c1 c0 0 将r0值传入c1协处理器
协处理器编程是一大方面,改天有时间再写。
通过比较使能cache与关闭cache我们可以看到,使能cache的情况下,明显的led闪烁的速度要快很多,所以这就是高速缓存的作用。
详细代码见git上bareOS中的cache目录
所有程序在github上,一直会更新至应用层,github地址https://github.com/kentGC/s5pv210,嵌入式交流学习qq群:363361058 欢迎各位大神交流!