举个例子:比如 addr1:0010 11010010 1110 addr2:1101 1111 1111 1010 cache 有8行。
划分内存地址 红色为标记位,黄色为块内偏移量。刚开始cache为空,访问addr1 addr2,不命中,从内存读取块,开始全相联映射,比如addr1,他属于块0010 1101 0000 0000 ----- 0010 1101 1111 1111,随机放入一行中,假设放入了101行,那么101行 也就是101 0000 0000 ----- 101 1111 1111这一行的标记位就为 0010 1101,同理 假设addr2放入的行是111,那么标记位就 为1101 1111,建立标记位和行的对应关系,相当于打表,表中有两项,0010 1101 对应 101 0000 0000,1101 1111对应 111 0000 0000 .第二次访问addr2的时候,遍历这张表,找到标记位与addr2前八位相同的表项 ,取出行号111 ,再与其块内偏移量一拼,就得到了cache中的地址111 1111 1010,这个地址上就是我们要访问的字。
2.直接映射
指的是 主存里的一个块能通过一个式子的映射能放在Cache中的一个特定的行里(这个逻辑由硬件实现)Cache的行号 i 和主存块号j存在关系 i=j mod n n为总行数,比如43号块,cache中有10行,说明43 必须放入第行号为3的那一行行,而且23 13 53等都是这样。
例子:
内存地址16位,Cache行数8行,内存地址低八位位块内地址,高八位位块号。这时,块号8位中的低三位,其实是块号除于八的余数(000-111),所以可以直接用内存地址当中的这三位来表示cache的行号,都不用算 ,结果剩下5位是标记位,内存的块往cache放的时候,内存地址的高八位中的的低三位是多少就往第几行放(硬件实现),吧剩下五位当做标记位,建立标记位与行的映射关系,便于查找。
原理。拿到16位地址之后,取出高八位的低三位确定行号去找第几行。吧这一行的标记位拿出来通过比较器和地址前五位比较,如果一样,则命中,不一样不命中,若命中,再根据块内地址(快内偏移)找到字送给cpu,不命中,访问内存,把包含这个字的整个块放到刚才我们找的那一行里面去(硬件实现)
比较器简单,只用比较两个数,但是不灵活,会产生抖动,冲突率最高,空间利用率最低。同时注意不需要替换算法。
举个例子:比如 addr1:0010 11010010 1110 addr2:1101 11111111 1010
两个内存地址:划分内存地址 红色为标记位,蓝色为行号,黄色为块内偏移量,cache一开始为空的时候 访问这个两个地址,不命中,开始直接映射,内存地址划分之后红色表示的是标记位,蓝色表示的是组好,黄色表示的是块内地址,那么addr1就是应该映射到行号为101的cache行,意思是整块映射到地址为101 0000 0000 -----101 1111 1111的cache行中, addr2 映射到行号为111的cache行,意思是整块映射到地址为111 0000 0000 -----111 1111 1111的行中,然后建立起标记位和行的对应关系,00101 对应101 0000 0000 (相当于把这一行的起始地址与标记位对应) 11011 对应111 0000 0000 ,当访问addr1的时候 获得组号10,查表,通过硬件直接得到 101行的标记位00101,命中,然后快内偏移位0010 1110 直接与101 连接起来 得到最终要的要访问的字所在的cache地址 101 0010 1110 。
3.组相联映射
是折中的方法,将cache的8行分为4组,没组2行,这叫做2路组相联,(一组4行叫做,4路组相联)。然后用内存地址的块号处于总组数,余数是几就往第几组放,组里面随便放。组内相当于全相联,组间直接映射。
内存地址,16位分隔为3部分:6位(直接作为标记位)+2位(用来确定组号)+块内8位。看组号是几,就放第几组,组里面随便放。将剩下6位当做cache标记位。二路组相联比一路的组号少一位,4路的少二位。。。类推
查找过程:获得16位内存地址,由组号是几就找第几组,将里面两个行的标记位和内存地址的前6位比较,如果有一个一样,说明命中。由块内地址找到字。两号标记位都不一样,就在内存中读出数据同时将字所在的整个块放到我们刚才找的那个组里面去,两行随便放(硬件实现)
举个例子:比如 addr1:0010 11010010 1110 addr2:1101 11111111 1010
两个内存地址:红色表示的是标记位,蓝色表示的是组好,黄色表示的是块内地址,第一次访问addr1 addr2 未命中,将内存块放入cache,那么addr1就是应该映射到组号为01的组,也就是第一组 意思在地址为010 0000 0000 ----- 010 1111 1111的cache行和地址为 011 0000 0000 ----- 011 1111 1111的cache行中, addr2 映射到组号为11的cache行,也就是第3组 意思是在地址为110 0000 0000 ----- 110 1111 1111的行以及111 0000 0000 ----- 111 1111 1111的行中。组内随便放,比如addr1 ,他所在的块0010 11 ...... 放入的是011 0000 0000 ---- 011 1111 1111的cache行中,那么他的这一行的标记位为0010 11,进建立对应关系,下次访问addr1的时候 直接得到组号,然后找到组好对应的两个行,取出标记位,与红色区域进行对比,然后与块内地址一拼接,就得到了字所在的地址。

计算问题

在cache的试题当中,我们会发现很多寸步难行的地方,主要的原因还是对于cache的地址的不了接所造成的。比如要你求cache的总容量你会怎么求呢。比如告诉你cache的总容量为16KB你就会说这么简单,不就是cache的地址是14位吗?的确有道理,因为不管你划分什么鬼标记位,块内地址,甚至是什么片选信号位,以及页号等等等,其实实质上都是一个地址对应一个字的数据,比如1100 1100 0011 0101这个地址,你无论怎么划分标记位什么的,其实就是相当于给整个存储系统分了几个部分。仅此而已,所以有道理。但是其实错了,为什么,这下我要告诉你cache的地址的真正构成,这个地方是本人经过很多题目的训练和网上寻找答案总结出来的东西,都是干货
大家都知道cache中的一行由标记位和块内地址组成,但是大家知道吗,其实一行中,有很多个字节,但是标记位只有一个,而不是每个字都对应一个相同的标记位。什么意思呢?就是cache的总容量首先有块内地址的容量,比如一个行长是64B的cahce,他的块内地址的容量就是512bit,这叫做每行存储的数据,也叫做数据块的位数但是在这一个快中,只有一个标记位,这个标记位,其实实质上不属于cache的地址。只是一个内容。(详情见王道P119)所以
cache的总容量=(有效位(每个行一般会加上一个有效位)+脏位+替换控制位+标记位的位数+数据块总位数。(一般题目会要求“若不考虑用雨cache的一致性维护和替换算法的控制位”,如果没有这个条件,但是他也没说写策略用的是哪个,或者没说替换策略用的是哪一个,那么久当做只有 有效位来处理))X行数;
所以,如有上面那句话,
cache的总容量=(有效位(每个行一般会加上一个有效位)+标记位位数+数据块总位数)X行数。
例:块长(有些书上称行为快)为64B(行长一般是K做单位,表示字的个数,但是题目有时候会用B ,bit KB MB这个意思就是一个行的有效容量,也就是一般所说的容量,还有数据块的位数),主存256MB,按字节编址(一般默认是这样,除非题目说明了按字编址或者说是出现了aMXbB这样的描述内存大小的方式)。有8行。求cache总容量和容量(若不考虑用雨cache的一致性维护和替换算法的控制位)
第一步一般求主存地址位数:主存256MB可得,256M=2的28次方,所以主存地址位数为28位。
第二部一般就块内地址位数:很可能用到行长来反推块长,因为两者相等。所以行长=块长=64,所以块内地址为6位。
第三部求标志位数(这个指的是主存地址的标志位,所以不用加1):28-行号位数(3位)-6(块内地址)=19位。
第四部求出cache行标记位的组成:19位+1,一定要注意加上有效位。
第五步求总容量=(20+64x8)x8
容量很简单1.块长x行数=64Bx8,
注意一般为cache的地址就是cache的块内地址。因为这才是他的有效数据位,还有问的是主存的标志位还是cache的标志位,还有就是块号和行号以及第几块一般是从0开始(一般题目会说,但是也可能不会说)
有一种情况就是告诉你cache的容量为16B这下你可以直接得出cache的地址位数为4位,如果是总容量就不行
关于最常考的关于c语言与cache的映射结合起来的方式,就是循环和求缺失率:
比如for(in=0;i