MIPS cache指令 .

http://blog.csdn.net/wyjie1987/article/details/6444769

 

MIPS cache指令:

指令编码:
31...26        25...21     20...16    15......0
CACHE(101111)  base        op          offset

格式:
cache op,offset(base)
执行op制定的cace操作,16位的offset经符号位扩展,添加到base寄存器以形成有效地址;
==========================================================
cache指令中的op字段低两位[17:16]表示操作的是哪个cache
2‘b00 I-L1(primary instruction)
2'b01 D-L1(primary data or unified primary)
2'b10    L3Cache(Tertiary)
2'b11 L2Cache(secondary)

cache指令中的op字段高三位[20:18]表示的是cache操作模式,比如:
HitInvalidate, HitWritebackInvalidate, IndexInvalid, IndexStoreTag等。主要表示命中类型(hit/miss)、是否是地址类型(正常的内存访问),是否是索引类型(操作index)。
需要注意的是,对于不同的cache,这高3位所代表的含义不同!
具体含义请查看:
《MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set》
==========================================================

对于loongson提供的pmon中的start_ls232_sm502.S文件中有关cache初始化代码,用到了以下3个宏定义:
#define Index_Store_Tag_D 0x09   // 0x09 = 0000 1001
#define Index_Invalidate_I 0X00 //  0x00 = 0000 0000
#define Index_Writeback_Inv_D 0x01 //  0x01 = 0000 0001
这3个宏是作为op来使用的,下面具体分析它们所代表的含义:
(1).Index_Store_Tag_D表示操作的是D-L1(L1的data cache,2’b01),操作模式是(3'b010)索引存储Tag,将TagLo和TagHi寄存器的值写入指定索引cache块的tag区(即D-L1的tag区)(该操作不允许引发异常);

有效地址操作类型:索引型

(2).Index_Invalidate_I表示操作的是I-L1(L1的instruction cache,2’b00),操作模式是(3’b000)索引作废,将指定索引的cache块状态设置为无效,常用于作废整个指令cache;

有效地址操作类型是:索引型

(3).Index_Writeback_Inv_D表示操作的是D-L1(L1的data cache,2’b01),操作模式是(3’b000)索引写回作废,对于写回型cache(龙芯的是写回型),如果索引的cache块状态为有效且脏,将该块数据写回内存。操作完成后,将该cache块置为无效,如果该块有效但不脏,仅将状态置为无效;

有效地址操作类型:索引型


Index Store Tag:
用TagLo/TagHi寄存器的值设置高速缓存标签!
要从未知状态初始化数据高速缓存,把TagLo/TagHi寄存器设为零,然后逐行进行该操作;

Index Invalidate:
设置该高速缓存行为无效,如果是D-Cache的行有效并且被修改过,那么先将其内容写入内存,再设为无效,这是初始化CPU时作废指令缓存最简单的方法;

Hit Writeback Invalidate:
作废该行,如果数据被污染,要先写回再作废,这是在运行中的数据高速缓存作废的推荐方法;
==========================================================

每种操作都有三种形式,区别在于怎样选择要操作的高速缓存项(即高速缓存行)的方式:
命中型---给出一个地址,从高速缓存中查找,如果找到(命中)则执行操作,否则什么也不干;
寻址型---给出内存中某个数据的地址,处理就和经过高速缓存访问一样,就是说,如果寻址的行不在高速缓存,那么在执行高速缓存操作之前要从内存中取出数据;
索引型---根据要用虚拟地址的低位依次选择高速缓存行内的字节,然后是高速缓存某一路内的行地址,然后是该路;


索引型作废、索引型存储tag、命中型写回作废这三种操作模式是必须实现的(对于MIPS32/64兼容型CPU);

==========================================================
cache数据更新方式
(1)关于回写型cache(write-back cache):
CPU只向cache写入,并用标记加以注明,直到cache中被写过的块要被进入的信息块取代时,才一次性写入主存;
(2)关于写透型cache(write-through cache):
CPU在向cache中写入数据的同时,也把数据写入主存以保证cache和主存中相应单元数据的一致性;

==========================================================
cache组织方式:
(1).全关连方式(fully associative):主存的区块可以映射到cache的任何一个地方;

(2).直接映射方式(direct mapped):主存的区块可以映射到cache的一个地方(惟一);
a.主存与缓存分成相同大小的数据块
b.主存容量是缓存容量的整数倍,将主存空间按缓存的容量分成区,主存中每一区的块数与缓存的总块数相等
c.主存中某区的一块存入缓存时只能存入缓存中块号相同的位置

存储块的位置:
(主存块号)mod(cache中的块数)

地址格式:
tag+index
tag用以标记主存的区是否与cache中缓存的区相匹配(主存按cache大小划分成区)
index用以在cache内寻址,查找对应于cache中的哪一块


(3).组相连方式(set associative):主存的区块可以映射到cache的有限的一个地方,在该方式下cache分为许多组,在一个组中有两个或多个区块,主存的区块映射到某个对应的组中,可以出现在该组的任何一个位置;
a.主存和cache按同样大小划分成块
b.主存和cache按同样大小划分成组
c.主存容量是缓存容量的整数倍,将主存空间按缓冲区大小划分成区,主存中每一区的组数与缓存的组数相同
d.当主存的数据调入缓存时,主存与缓存的组号应相等,也就是各区中的某一块只能存入缓存的同组号的空间内,但组内各地址之间可以任意存放;
即主存的组到cache的组之间采用的是直接映射,在两个对应的组内部采用的是全相连映射;

包含存储块的组:
(块号)mod(cache中组的个数)


n路组关联:
每个块有n个位置可放置的组关联cache

可以把直接映射看成是一路组相连,把含有m块的全关连cache视为m路组关联;

提高关联度能增大命中,但是也增加了命中时间;


地址格式:
tag     index   selector
高地址部分用作tag,低地址部分用作index和selector

==========================================================


初始化程序:
1.开辟一些内存以便可以从它来填充高速缓存。存入什么数据没有关系。一个好的窍门是至少到高速缓存初始化之前预留系统内存的低32K(0x8000)用于此目的;

2.将TagLo寄存器设为零,这样能保证对应行有效的那一位不会置位并且Tag(标签)的奇偶码是一致的,
TagLo寄存器将被cache IndexStoreTag指令用来强制作废对应的高速缓存行并清除标签的奇偶校验位。

3.禁止中断

4.先初始化I-Cache,然后是D-Cache,下面是初始化I-Cache的C代码:
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
  /*clear tag to invalidate*/
  Index_Store_Tag_I(addr);
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
  /*fill once,so data field parity is correct*/
  Fill_I(addr);
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
  /*invalidate again, prudent but not strictly necessay*/
  Index_Store_Tag_I();
  
5.D-Cache的初始化
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
/*clear all tags*/
  Index_Store_Tag_D(addr);
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
/*load from each line(in cached space)*/
  junk = *addr;
for(addr = KSEG0; addr < KSEG0+size; addr += lnsize)
  Index_Store_Tag_D(addr);
  
==========================================================
cache的行匹配和字选择:

cache格式:
-----------------------------------
|有效位  tag  高速缓存块(存放数据)|------>cache的一行
-----------------------------------


地址格式:
高位          低位
----------------------------
tag......index......selector

1.全相连

全相连的地址格式与其它两个不一样,全相连可以看成是只有一个组,所以就不需要index了:

高位          低位
----------------------------
tag.................selector

对每一行进行tag匹配(只有一个组)
若tag匹配成功,则利用selector找出字;


2.直接映射
首先利用index找出组;
比较tag(直接映射每组只有一行);
若tag匹配成功,则利用selector找出字;

3.组相连映射
首先利用index找出组;
对组中的每一行,比较tag;
若tag匹配成功,则在该行中利用selector找出字;

 

 

http://rf.eefocus.com/article/10-07/1968501280485418.html?sort=1751_1812_0_0

cache指令的形式和MIPS的load/store指令的通用形式相同(采用通常的寄存器加上十六位有符号数的偏移量进行寻址)― 但是对应于数据寄存器编码的地方是个5位的操作域,用以编码待操作的高速缓存、确定怎样找到相应高速缓存行、以及找到相应行之后怎么处理。用cache OP , addr这样的汇编代码写入高速缓存行,其中OP只是一个代表操作域的数值。

最好的做法就是使用一个C语言的预处理程序定义一个文本的“名字”代表相应操作的数值。对此没有标准的命名;我就随便用了在MIPS开发工具包的头文件里找到的C预处理中定义的名字。
该5位域的高2位选择要操作的是哪个高速缓存:
O = L1 I-cache
l = L1 ID-cache
2 = L3如果有的话
3 = L2如果有的话
在我们列出这些操作之前,先说明一下,每个操作都有三种形式,区别在于怎样选择要操作的高速缓存项(即高速缓存行)的方式:

命中型操作:给出一个地址从高速缓存中查找。如果找到(即“命中”)则执行操作,否则什么也不干。
寻址型操作:给出内存中某个数据的地址,处理就和经过高速缓存访问一样。就是说,如果你寻址的行不在高速缓存,在执行高速缓存操作之前要从内存取出数据。
索引型操作:根据需要用虚拟地址的低位依次选择高速缓存行内的字节,然后是高速缓存某一路内的行地址,然后是该路。“你必须知道高速缓存的大小才能知道各个域的确切边界,但地址用法跟下面差不多,如图3.3:

一旦选定了相应的高速缓存以及某一行,你有几个操作可以选择。CPU必须支持这三种操作才算得上是MIPS32/64兼容的:索引型作废、索引型存储标签、命中型回写作废。其余操作都是可选的一一如果要用的话,请仔细对照CPU手册。
synci指令为保证你刚刚写入的指令能够正确执行(合并了一个D-cache回写和I-cache作废操作)提供了一个明确清晰的机制。只要你的CPU支持,就应当使用synci而不是传统的替代方案(用一对cache指令来做:D-cache回写后跟一个I-cache作废)。

 

你可能感兴趣的:(龙芯之旅)