tiny4412开发板icache操作程序

Source

首先,来介绍关于cache的概念。

cache的作用:

基于程序访问的局限性,在主存和CPU通用寄存器之间设置了一个高速的、容量相对较小的存储器,把正在执行的指令地址附近的一部分指令或数据从主存调入这个存储器,供CPU在一段时间内使用,这对提高程序的运行速度有很大的作用。这个介于主存和CPU之间的高速小容量存储器称作高速缓存存储器(Cache)。

启用Cache后,CPU读取数据时,如果Cache中有这个数据的复本则直接返回,否则从主存中读入数据,并存入Cache中,下次再使用(读/写)这个数据时,可以直接使用Cache中的复本。

启用Cache后,CPU写数据时有写穿式和回写式两种方式。

(1)写穿式(Write Through)
任一从CPU发出的写信号送到Cache的同时,也写入主存,可以保证主存的数据能同步地更新。它的优点是操作简单,但由于主存的慢速,降低了系统的写速度并占用了总线的时间。

(2)回写式(Write Back)
为了克服贯穿式中每次数据写入时都要访问主存,从而导致系统写速度降低并占用总线时间,尽量减少对主存的访问次数,又有了回写式。

它是这样工作的:数据一般只写到Cache,这样有可能出现Cache中的数据得到更新而主存中的数据不变(数据陈旧)的情况。但此时可在Cache中设一标志地址及数据陈旧的信息,只有当Cache中的数据被换出或强制进行清空操作时,才能将更新的数据写入主存相应的单元中。这样保证了Cache和主存中的数据一致。

先介绍Cache的两个操作。
(1)清空:把Cache或Write buffer中已经脏的(修改过,但未写入主存)数据写入主存。
(2)使无效:使之不能再用,并不将脏的数据写入主存。

ICache的使用比较简单。系统刚上电或复位时,ICache中的内容是无效的,并且ICache功能是关闭着的。往Icr(CP15协处理器中寄存器1的第12位)写1可以启动ICache,写0可以停止ICache。

ICache一般在MMU开启之后被使用,此时页表中描述符的C位用来表示一段内存是否可以被ICache。若Ctt=1,则允许ICache,否则不允许被ICache。但是,即使MMU没有开启,ICache也可以被使用的,这时CPU读取指令时所涉及的内存都被当做是允许ICache的。

ICache被关闭时,CPU每次读取指令都读取主存,性能非常低。所以,通常尽早启动ICache。

ICache被开启后,CPU每次读取指令时都会先在ICache中查看是否能找到所要的指令,而不管Ctt是0还是1。如果找到了,称为Cache命中,如果找不到,称为Cache缺失。ICache被开启后,CPU的取指分为如下3种情况。

(1)Cache命中且Ctt为1时,从ICache中取出指令,返回给CPU。
(2)Cache缺失且Ctt为1时,CPU从主存中读出指令。同时,一个被称为"8-word linefill"的动作将发生,这个动作把该指令所处区域8个word写进ICache的某个条目中。这有可能会覆盖某个条目,可以使用Pseudo-random算法或round-robin算法在ICahe中选出某个没有被锁定的条目。可以通过CP15协处理器中寄存器1的第14位来选择使用哪种算法。
(3)Ctt为0时,CPU从主存中读取指令。

OK,关于Cache的基本知识已经介绍完毕了。要开启DCache需要先开启MMU,所以这里我们只讲解关于ICache的操作。

在上面已经介绍了,如果要开启ICache,需要操作CP15协处理的寄存器1的bit12,写入1表示开启,写入0表示关闭。

先来看两条操作CP15协处理器的指令:MCR和MRC指令。

MCR:

MCR指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。
指令的语法格式:

MCR{<cond>} p15, {opcode_1} , <Rd>, <CRn>, <CRm> {,<opcode_2>}

其中,<cond>为指令执行的条件码。当<cond>忽略时指令为无条件执行。

<opcode_1>为协处理器将执行的操作的操作码。对于CP15协处理器来说,<opcode_1>永远为0b000,当<opcode_1>不为0b000时,该指令操作结果不可预知。

<Rd>作为源寄存器的ARM寄存器,其值被传送到得协处理器寄存器中。<Rd>不能为PC,当其为PC时,指令操作结果不可预知。

<CRn>作为目标寄存器的协处理器寄存器,其编号可能为C0,C1....C15。

<CRm>附加的目标寄存器或者原操作数寄存器,用于区分同一个编号的不同物理寄存器。当指令中不需要提供附加信息时,将C0指定为<CRm>,否则指令操作结果不可预知。

<opcode_2>提供附加信息,用于区别同一个编号的不同物理寄存器。当指令中指定附加信息时,省略<opcode_2>或者将其指定为0,否则指令操作结果不可预知。否则指令操作结果不可预知。

MRC:

MRC指令将协处理器的寄存器中数值传送到ARM处理器的寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。
指令的语法格式:

MRC{<cond>} p15, {opcode_2}, <Rd>, <CRn>, <CRm> {,<opcode_2>}

操作ICache程序示例;

我们使用前面操作LED循环点亮的程序。首先,不开启ICache,查看LED的亮灭时间间隔。然后开启ICache,查看LED的亮灭时间间隔。

start.S文件内容如下:

.text
.global _start
_start:
	//注意:在芯片的iROM中已经开启了ICache;即使这里开启也观察不到什么变化;
	//所以这里将ICache关闭,观察LED的亮灭情况;可以和原来的对比发现,速度慢了很多
	//将CP15协处理器的C1寄存器的值保存到R0寄存器中
	mrc p15, 0, r0, c1, c0, 0
	//将R0中的数据的BIT12置0
	bic r0, r0, #0x00001000
	//将R0中的数据写回CP15协处理器的C1寄存器中
	mcr p15, 0, r0, c1, c0, 0
	
	ldr sp, =0x02027400		//设置栈
	
	bl main					//跳转到mian函数开始执行
	
halt_loop:					//死循环
	b halt_loop

上面的程序中已经做了详细的注释,将ICache禁止了。可以将程序编译并烧写。查看LED的闪亮时间间隔。发现和原来的程序相比LED闪亮周期大了很多。

本文完毕!