3C定理

  • 影响Cache miss的三种情况
  • Compulsory:一定会发生miss,但是可以通过prefetching(预取指)来减少发生miss的频率
  • Capacity:容量
  • Conflict:冲突,除非一一映射,总会有少数情况会发生两个数据映射到同一个block中,这时候可以使用Victim Cache来减少冲突

规格与组成

  • Cache由SRAM组成
  • 一个Cache有多个Set
  • 一个Set有多路Cacheline
  • 一个Cacheline有多个字段
  • Valid:当前行是否有效
  • Tag:唯一标记一个Cacheline
  • Cache Block:一行数据

映射方式

1. 直接映射

  • 地址形式:[Tag,SetIndex,BlockOffset]
  • Cache形式:
  • 一个Cache有S个Set => Set = Cache[S]
  • 一个Set只有一个Cacheline => Cacheline=Set[0]
  • 所以所有SetIndex相同的,都会访问同Set的同一个Cacheline,去匹配再访存,产生了较大的Conflict

  • Set selection:Set = Set[SetIndex]

  • Cacheline selection:Cacheline = Cache[S]
  • line matching
    • isValid = Cacheline.Valid
    • isMatch = Cacheline.Tag == Tag
    • if(isValid && isMatch) [Hit] else [Miss]
  • word extract

2. 组相连

  • 地址形式:[Tag,SetIndex,BlockOffset]
  • 一路就是一个Cacheline的意思
  • Cache形式:
  • 一个Cache有S个Set => Set = Cache[S]
  • 一个Set有W个Cacheline => Cacheline = Set[W]
  • 地址中不记录数据存放在哪一路:所以所有SetIndex相同的,由于不知道存放在哪一路,会先遍历每一路Cacheline,每次匹配Tag,成功再访存,减少了一定的Conflict

  • Set selection:Set = Cache[SetIndex]

  • Cacheline selection:for(w:0->W) Cacheline = Set[w]
  • line matching
    • isValid = Cacheline[w].Valid
    • isMatch = Cacheline[w].Tag == Tag
    • if(isValid && isMatch) [Hit] else [Miss]
  • word extract

3. 全相联

  • 地址形式:[Tag,BlockOffset]
  • Cache形式:
  • 一个Cache只有一个Set => Set = Cache[0]
  • 一个Set有W个Cacheline => Cacheline = Set[W]
  • Set selection:Set = Cache[0]
  • Cacheline selection:for(w:0->W) Cacheline = Set[w]
  • line matching
  • word extract

读Cache

  • ReadHit
  • data = Cacheline.block[BlockOffset:End]
  • ReadMiss
  • ReadAllocate:当Miss时,内存先同步数据给Cache,然后CPU再读入Cache的数据

写Cache

1. WriteHit

  • WriteThrough
  • CPU写入Cache,然后Cache立即同步给内存
  • CPU需要该数据时,可以直接在Cache中命中,因此一定可以拿到新数据
  • Cache会占用总线,使得速度较慢
  • WriteBack
  • CPU将新数据写入Cache,并将该cacheline标记为dirty,Cache需要被替换时才将新数据同步给内存,然后清除dirty
  • 替换前:CPU需要该数据时,可以直接在Cache中命中,因此一定可以拿到新数据
  • 替换后:CPU需要该数据时,Cache一定会Miss,但由于Cache替换后已经将新数据写入内存,因此执行WriteMiss一定可以拿到新数据

2. WriteMiss

  • WriteAllocate(内存分配给Cache)
  • 当Miss时,内存先同步旧数据给Cache,然后CPU再修改Cache为新数据(修改旧数据的一部分->新数据)
  • 当CPU下次需要读该数据时,一定会ReadHit,因此一定会读入Cache中的新数据,而不是内存中的旧数据
  • NonWriteAllocate(内存不分配给Cache)
  • 当Miss时,CPU直接将新数据写入内存
  • 当CPU下次需要读该数据时,一定会ReadMiss,因此一定会读入内存中的新数据,而不是Cache的旧数据

3. 组合

  • 一般WT和NonWriteAllocate连用,WB和WriteAllocate连用,因为可以复用彼此的数据通路

替换算法

  • 基本概念
  • 什么时候用替换算法:当Cache满,但还需要写入Cache的时候
  • 替换什么:每次替换一个Cacheline

  • Random

  • LRU
  • 给每一个Cacheline增加一个age-bit,它记录“剩余时间”
  • 当数据进入Cacheline时,age-bit赋初始值为T,每次读写后,未使用的数据age-bit--,使用的数据age-bit=T
  • 当需要替换时,优先替换age-bit最少的

Cache实现原理

流水线拆分

  • 实现:ICache、DCache,它们需要并行访问或者串行访问,因此需要在地址计算之后,增加一个相关性检查的阶段

1. 并行读(assume Set-Associated Cache)

  • Addr Calculation
  • 计算地址,地址包含Tag、SetIndex、Offset
  • Disambiguation
  • 将SetIndex进行decode,进行相关性检查
  • Cache(Tag&Data) Access
  • 选中SetIndex的组,取出每一个Cacheline的Block部分,作为一个Array
  • 选中SetIndex的组,取出每一个Cacheline的Tag部分,作为一个Array
  • 将Block和Tag部分进行Mux,最终得到Hit/Miss,并给出取出的数据
  • Result Drive
  • 输出Hit/Miss
  • 将得到的数据,进行Data Align(即根据Offset选中数据的部分作为输出)

2. 串行读

  • 和并行访问差不多,只是必须先计算Tag再计算Block,而不能同时计算
  • Addr Calculation
  • Disambiguation
  • Tag Access
  • Data Access
  • Result

多端口Cache

  • 目的:超标量cpu有时会在1clk中同时发出多个load和store请求,如果cache支持1clk接收多个ls,可以加快处理速度

1. True Port

  • 注:这个实现太慢且面积太大,不建议使用。
  • 需要cache中的每一个SRAM cell都支持dual-port read/write
  • 还需要设计两个Mux、Decoder等

2. Multiple Cache Copies

  • 在一个Cache中设计两个Cache(=2tag+2data),支持1个store和2个load
  • 仍然需要设计两个Mux、Decoder等
  • 这种方法就不需要sram支持dual-port read/write了
  • 但是这种方法在store时需要维护两个cache之间的一致性,每次写入都相当于同时写两次。

3. Multi-banking

  • 将cache分为两个区域bank0、bank1
  • 当端口之间访问的bank不同时(no-bank-conflict),两个bank可以并行响应两个端口
  • 当端口之间访问的bank相同时(bank-conflict),此时一个bank只能响应一个端口