如果没有局部性,cache将毫无用处,因为CPU所需的操作数或指令在cache中的概率太小。由于局部性的存在,cache可以包含主存的相对较小的子集。
仅在cache中保存主存的子集需要一个特殊的cache结构,这个结构比主存储器结构稍微复杂一些。除了保存主存的子集外,cache还应该保存告诉我们子集在cache中的其他信息。因此,cache由两部分组成:控制部分和数据部分。
数据部分包含cacheline。cacheline是cache中的基本存储单元。cacheline是固定大小的数据部分,从主存或内存层次结构的较低级别中检索出来。每个cacheline包含从主存获取的连续数据或指令。现代计算机中常见的cacheline大小是64字节,因此,其地址仅在较低的六位上有所不同。
cacheline是可以在cache和主存之间传输的最小数据单元。当数据从主存中获取或写入时,是以整个cacheline为单位进行的,即使只需要cacheline的一部分。
控制部分包含用于管理和识别cache内容的cache标签tag和有效位valid bit。tag是cacheline在主存中的地址。tag对于确定请求的内存位置是否在cache中(hit和miss)至关重要,方法是将请求的内存地址与cache中存储的tag进行比较。
除了cache tag外,每个cacheline还包含一个有效位valid bit。有效位指示cacheline中的数据是否有效并可以使用。如果设置了有效位,则数据有效并可以用于内存访问。有效位有助于确保cache的一致性。
上图展示了一个简单的cache结构及其操作。这个cache仅包含八个cacheline,每个cacheline存储八个8位。在此示例中,CPU地址为16位长,最低三位确定cacheline内存的偏移量。由于cache中有八个cacheline,接下来的三位地址位(位5到3)确定cacheline在cache中的索引。其余的十个最高有效位确定主存中cacheline的地址,也就是tag。
当CPU发出内存访问请求时,cache控制器提取内存地址的tag部分,并将其与由内存地址确定的cacheline中的tag进行比较。cache控制器执行比较以确定请求的数据是否在cache中。
如果从内存地址中提取的tag与特定cacheline中存储的tag匹配,并且有效位已设置(表示有效数据),则是cache命中。然后从cache中获取请求的数据,为CPU提供更快的访问。
如果tag不匹配或有效位未设置(表示cacheline无效),则是cache未命中。在这种情况下,cache控制器必须从较慢的存储器级别获取数据以满足CPU的请求。检索到的数据块被放置在cache中以供将来访问。
由于主存储器中的每个数据块都映射到由地址中的三位(5到2)确定的恰好一个cacheline,我们说这个cache是直接映射的。在直接映射cache中,主存储器块和cache块之间存在一一对应关系,使其成为最简单的cache组织形式之一。