Overview
Cache主要用于提供高速存储访问,是利用数据的时间局部性和空间局部性而设计的小存储单元。即用一块更小更快的存储设备作为更大更慢的存储设备的缓冲区,从而提高数据访问速度。本文实现了一种高性能可配置的Cache,采用独立模块化设计,前端接口支持AHB4,后端接口支持AXI4。
System Block Diagram
Figure 3-2-1. Cache block diagram
Cache由4个独立的模块组成:ahb2front、front_end、cache_memory和back_end模块。ahb2front模块完成AHB port和native port间的转换;front_end模块完成native port的处理,back_end模块连接下级存储器,完成AXI port的处理。cache_memory模块位于front_end和back_end模块之间,包含所有的控制逻辑和可用Memory单元。
在处理器读Cache的过程中,根据主存地址判断数据是否在此Cache中。如果在此Cache发现数据,则将数据传输给处理器;若在此Cache中没有发现数据,则在下级存储器中寻找,最后再把数据所在的块调入Cache。
Key Features
支持AHB4的前端接口和AXI4的后端接口,数据位宽为64bits;
AHB支持任意burst type,AXI支持single和incr;
支持直接映射和多路组相连映射;
支持LRU、PLRU_mru和PLRU_tree等替换算法;
支持write through和write back两种更新策略;
支持读分配和写分配;
支持clean和invalid功能;
Data Memory支持ECC校验;
支持trans count计数功能,包括write hit count、write miss count、read hit count、read miss count、hit count、miss count、trans count等;
Interface
| Parameter**** | Description**** |
|---|---|
| FE_ADDR_W | 读写cache地址位宽 |
| FE_DATA_W | 读写cache数据位宽(8的倍数) |
| N_WAYS | 组相联映射的组数,值是2的幂,取值是1的时候,表示直接映射 |
| LINE_OFF_W | index字段 width,cache lines总数为N_WAYS*2LINE_OFF_W |
| WORD_OFF_W | offset字段width,每个cache line数据位宽是FE_ADDR_W*WORD_OFF_W |
| WTBUF_DEPTH_W | Write-Through-Buffer FIFO深度 |
| REP_POLICY | LRU (0); PLRU_mru (1); PLRU_tree (2) |
| WRITE_POL | 写策略,write-through (0), write-back (1) |
| AXI_ID_W | AXI_ID数据位宽 |
| AXI_ADDR_W | AXI读写主存地址位宽 |
| AXI_DATA_W | AXI读写主存数据位宽 |
| AXI_LEN_W | AXI突发长度位宽 |
| Interface**** | Width**** | IN /OUT**** | Description**** |
|---|---|---|---|
| clk | 1 | IN | 系统时钟 |
| rst_n | 1 | IN | 系统复位 |
| idle | 1 | OUT | idle状态指示信号 |
| haddr | FE_ADDR_W | IN | WRITE AHB address |
| hburst | 3 | IN | WRITE AHB burst type |
| hprot | 4 | IN | WRITE AHB transfer protection ctrl |
| hsize | 3 | IN | WRITE AHB transfer size |
| htrans | 2 | IN | WRITE AHB transfer type |
| hwdata | FE_DATA_W | IN | WRITE AHB write data |
| hwrite | 1 | IN | WRITE AHB transfer direction |
| hrdata | FE_DATA_W | OUT | WRITE AHB read data |
| hready | 1 | OUT | WRITE AHB transfer ready |
| hresp | 1 | OUT | WRITE AHB transfer error |
| m_axi_awid | AXI_ID_W | OUT | Address write channel ID |
| m_axi_awaddr | AXI_ADDR_W | OUT | Address write channel address |
| m_axi_awlen | AXI_LEN_W | OUT | Address write channel burst lengh |
| m_axi_awsize | 3 | OUT | Address write channel burst size |
| m_axi_awburst | 2 | OUT | Address write channel burst type |
| m_axi_awlock | 2 | OUT | Address write channel lock type |
| m_axi_awcache | 4 | OUT | Address write channel memory type |
| m_axi_awprot | 3 | OUT | Address write channel protection type |
| m_axi_awqos | 4 | OUT | Address write channel quality of service |
| m_axi_awvalid | 1 | OUT | Address write channel valid |
| m_axi_awready | 1 | IN | Address write channel ready |
| m_axi_awuser | 1 | OUT | Address write channel user defined |
| m_axi_awregion | 4 | OUT | Address write channel multiple region |
| m_axi_wdata | AXI_DATA_W | OUT | Write channel data |
| m_axi_wstrb | AXI_DATA_W/8 | OUT | Write channel write strobe |
| m_axi_wlast | 1 | OUT | Write channel last word flag |
| m_axi_wvalid | 1 | OUT | Write channel valid |
| m_axi_wready | 1 | IN | Write channel ready |
| m_axi_wuser | 1 | OUT | Write channel user defined |
| m_axi_bid | AXI_ID_W | IN | Write response channel ID |
| m_axi_bresp | 2 | IN | Write response channel response |
| m_axi_bvalid | 1 | IN | Write response channel valid |
| m_axi_bready | 1 | OUT | Write response channel ready |
| m_axi_buser | 1 | IN | Write response channel user defined |
| m_axi_arid | AXI_ID_W | OUT | Address read channel ID |
| m_axi_araddr | AXI_ADDR_W | OUT | Address read channel address |
| m_axi_arlen | AXI_LEN_W | OUT | Address read channel burst lengh |
| m_axi_arsize | 3 | OUT | Address read channel burst size |
| m_axi_arburst | 2 | OUT | Address read channel burst type |
| m_axi_arlock | 2 | OUT | Address read channel lock type |
| m_axi_arcache | 4 | OUT | Address read channel memory type |
| m_axi_arprot | 3 | OUT | Address read channel protection type |
| m_axi_arqos | 4 | OUT | Address read channel quality of service |
| m_axi_arvalid | 1 | OUT | Address read channel valid |
| m_axi_arready | 1 | IN | Address read channel ready |
| m_axi_aruser | 1 | OUT | Address read channel user defined |
| m_axi_arregion | 4 | OUT | Address read channel multiple region |
| m_axi_rdata | AXI_DATA_W | IN | Read channel data |
| m_axi_rstrb | AXI_DATA_W/8 | IN | Read channel write strobe |
| m_axi_rlast | 1 | IN | Read channel last word flag |
| m_axi_rvalid | 1 | IN | Read channel valid |
| m_axi_rready | 1 | OUT | Read channel ready |
| m_axi_ruser | 1 | IN | Read channel user defined |
| invalidate | 1 | IN | total cacheline invalid信号 |
| clean | 1 | IN | total cacheline clean信号 |
| cnt_en | 1 | IN | trans/hit/miss计数使能 |
| cnt_clr | 1 | IN | trans/hit/miss计数清零 |
| write_hit | 1 | OUT | 当前haddr write hit标志信号 |
| write_miss | 1 | OUT | 当前haddr write miss标志信号 |
| read_hit | 1 | OUT | 当前haddr read hit标志信号 |
| read_miss | 1 | OUT | 当前haddr read miss标志信号 |
| write_hit_cnt | FE_DATA_W | OUT | write hit计数 |
| write_miss_cnt | FE_DATA_W | OUT | write miss计数 |
| read_hit_cnt | FE_DATA_W | OUT | read hit计数 |
| read_miss_cnt | FE_DATA_W | OUT | read miss计数 |
| hit_cnt | FE_DATA_W | OUT | read和write hit计数 |
| miss_cnt | FE_DATA_W | OUT | read和write miss计数 |
| trans_cnt | FE_DATA_W | OUT | trans总计数 |
| cache_ecc_en | 1 | IN | data memory ECC使能 |
| cache_one_ecc_err | 1 | OUT | data memory 单个错误标志 |
| cache_two_ecc_err | 1 | OUT | data memory 两个错误标志 |
Cache memory
cache_memory模块位于front_end和back_end模块之间,包含所有的控制逻辑和可用memory单元。其中,多个memory单元可分别存储Tag、Valid、Data等,还包括write through buffer和replacement policy memory。根据参数配置,Cache可实现直接映射或多路组相联映射,以及LRU、PLRU_mru或PLRU_tree等替换策略。
Cache memory interface
| Interface**** | Width**** | IN /OUT**** | Description**** |
|---|---|---|---|
| clk | 1 | IN | 时钟 |
| reset | 1 | IN | 复位 |
| idle | 1 | OUT | idle状态指示信号 |
| valid | 1 | IN | 读写请求有效 |
| addr | FE_ADDR_W | IN | native port 读写地址 |
| wstrb | FE_NBYTES | IN | native port 写选通 |
| rdata | FE_DATA_W | OUT | native port 读数据 |
| ready | 1 | OUT | native port ready |
| valid_reg | 1 | IN | 由Front_end输入,数据有效标志,用来store data |
| addr_reg | FE_ADDR_W-FE_BYTE_W | IN | 由Front_end输入,数据地址,用来store data |
| wdata_reg | FE_DATA_W | IN | 由Front_end输入,写数据,用来store data |
| wstrb_reg | FE_NBYTES | IN | 由Front_end输入,写选通,用来store data |
| write_valid | 1 | OUT | 输出至Back_end,写有效 |
| write_addr | FE_ADDR_W-FE_BYTE_W-WRITE_POL*WORD_OFF_W | OUT | 输出至Back_end,写地址 |
| write_wdata | FE_DATA_W+WRITE_POL*(FE_DATA_W*(2**WORD_OFF_W)-FE_DATA_W) | OUT | 输出至Back_end,写数据 |
| write_wstrb | FE_NBYTES | OUT | 输出至Back_end,写选通 |
| write_ready | 1 | IN | 由Back_end输入,写通道处于空闲状态 |
| replace_valid | 1 | OUT | 输出至Back_end,替换有效标志 |
| replace_addr | FE_ADDR_W-BE_BYTE_W-LINE2MEM_W | OUT | 输出至Back_end,替换数据地址 |
| replace | 1 | IN | 由Back_end输入,数据替换完成 |
| read_valid | 1 | IN | 由Back_end输入,读取数据有效 |
| read_addr | LINE2MEM_W | IN | 由Back_end输入,axi read burst中每次读取的位宽是BE_DATA_W的数据在需替换cache line中的offset(arlen = 2^LINE2MEM_W-1) |
| read_rdata | BE_DATA_W | IN | 由Back_end输入,读取数据 |
| invalidate | 1 | IN | total cacheline invalid信号 |
| clean | 1 | IN | total cacheline clean信号 |
| cnt_en | 1 | IN | trans/hit/miss计数使能 |
| cnt_clr | 1 | IN | trans/hit/miss计数清零 |
| write_hit | 1 | OUT | 当前haddr write hit标志信号 |
| write_miss | 1 | OUT | 当前haddr write miss标志信号 |
| read_hit | 1 | OUT | 当前haddr read hit标志信号 |
| read_miss | 1 | OUT | 当前haddr read miss标志信号 |
| write_hit_cnt | FE_DATA_W | OUT | write hit计数 |
| write_miss_cnt | FE_DATA_W | OUT | write miss计数 |
| read_hit_cnt | FE_DATA_W | OUT | read hit计数 |
| read_miss_cnt | FE_DATA_W | OUT | read miss计数 |
| hit_cnt | FE_DATA_W | OUT | read和write hit计数 |
| miss_cnt | FE_DATA_W | OUT | read和write miss计数 |
| trans_cnt | FE_DATA_W | OUT | trans总计数 |
| cache_ecc_en | 1 | IN | data memory ECC使能 |
| cache_one_ecc_err | 1 | OUT | data memory 单个错误标志 |
| cache_two_ecc_err | 1 | OUT | data memory 两个错误标志 |
| wtbuf_full | 1 | OUT | write through buffer full标志信号 |
| wtbuf_empty | 1 | OUT | write through buffer empty标志信号 |
| buffer_full_pre | 1 | OUT | write through buffer pre full,提前一拍 |
| buffer_wen | 1 | IN | write through buffer写使能 |
Memory Information
多路组相联映射的每一路都有一个Tag Memory和Data Memory,这些可用Memory均是Single Port。Tag Memory的宽度等于Tag的数据位宽,深度等于每一路中cache line的数量。Tag Memory有一个时钟周期的读取延迟。Valid Memory由1bit的寄存器(register file)组成,其长度等于每一路中cache line的数量,系统重置或Cache invalid期间可将其内容设置为0。Data Memory的宽度是FE_DATA_W,深度等于每一路中cache line的数量,通过wstrb写选通信号可以选择要存储的字节。Write-Through-Buffer用同步FIFO实现,要求数据在其被读取后的一个时钟周期上可用,存储addr、wdata、wstrb。
输入的地址信号被分成tag、index和offset三部分。该地址用于Tag Memory、Valid Memory和Data Memory等的寻址。hit或miss是Tag匹配的结果。wstrb_reg的任一bit不为0时,处于写Cache的阶段;wstrb_reg为0时,处于读Cache的阶段。
如果读请求命中,表示请求数据在Data Memory中已存在。Data Memory的输入数据有两种情况,一是back_end读取数据,二是front_end写入数据。replace信号为1时,back_end的读通道控制器已启动,Data Memory中的cache line需要被替换,输入数据是back_end读取数据;replace信号为0时,Data Memory中的cache line不需要被替换,输入数据是front_end写入数据。当发生read miss,replace_valid信号为高,Tag Memory和Valid Memory都需要被更新。当前没有进行到主存的写传输时,才能开始替换。
write_valid和write_ready信号构成了作用于back_end写通道的握手对。write_valid表示Write-Through-Buffer不为空。write_ready表示back_end写通道处于空闲状态,可以读取Write-Through-Buffer。
写请求不依赖于Cache中的可用数据,此时遵循写不分配的写策略,需考虑Write-Through-Buffer的可用空间。write hit时,为避免停止,Data Memory使用*_reg的输入信号去存储数据,这样Cache能够接收新的请求。
要求在与主存的写传输之后才开始cache line替换是为了避免读写一致性的问题。
如果写请求后紧跟一个读请求,可能会出现Read-After Write (RAW)的问题。因读请求的数据可能在前一时钟刚刚写入,与此同时,这一时钟周期上的memory输出是不可用的,那么这时Cache的工作需要中止。如果每一个write hit后的读请求都会引起Cache中止,Cache性能会受到严重影响。因此,本IP设计实现只有访问多路组相联映射的同一路中的cache line,并且offset相同时(即访问Data Memory中相同的一块子SRAM时),指示发生RAM的信号才会拉高。
back_end
back_end模块连接更高一级存储器,接口为AXI4,包含写通道控制器和读通道控制器。
| Interface**** | Width**** | IN /OUT**** | Description**** |
|---|---|---|---|
| clk | 1 | IN | 时钟 |
| reset | 1 | IN | 复位 |
| write_valid | 1 | IN | 输出至Back_end,写有效 |
| write_addr | FE_ADDR_W-FE_BYTE_W-WRITE_POL*WORD_OFF_W | IN | 由Cache_Memory输入,写地址 |
| write_wdata | FE_DATA_W+WRITE_POL*(FE_DATA_W*(2**WORD_OFF_W)-FE_DATA_W) | IN | 输出至Back_end,写数据 |
| write_wstrb | FE_NBYTES | IN | 输出至Back_end,写选通 |
| write_ready | 1 | OUT | 由Back_end输入,写通道处于空闲状态 |
| replace_valid | 1 | IN | 输出至Back_end,替换有效标志 |
| replace_addr | FE_ADDR_W-BE_BYTE_W-LINE2MEM_W | IN | 输出至Back_end,替换数据地址 |
| replace | 1 | OUT | 由Back_end输入,数据替换完成 |
| read_valid | 1 | OUT | 由Back_end输入,读取数据有效 |
| read_addr | LINE2MEM_W | OUT | 由Back_end输入,axi read burst中每次读取的位宽是BE_DATA_W的数据在需替换cache line中的offset(arlen = 2^LINE2MEM_W-1) |
| read_rdata | BE_DATA_W | OUT | 由Back_end输入,读取数据 |
| m_axi_awid | AXI_ID_W | OUT | Address write channel ID |
| m_axi_awaddr | AXI_ADDR_W | OUT | Address write channel address |
| m_axi_awlen | AXI_LEN_W | OUT | Address write channel burst lengh |
| m_axi_awsize | 3 | OUT | Address write channel burst size |
| m_axi_awburst | 2 | OUT | Address write channel burst type |
| m_axi_awlock | 2 | OUT | Address write channel lock type |
| m_axi_awcache | 4 | OUT | Address write channel memory type |
| m_axi_awprot | 3 | OUT | Address write channel protection type |
| m_axi_awqos | 4 | OUT | Address write channel quality of service |
| m_axi_awvalid | 1 | OUT | Address write channel valid |
| m_axi_awready | 1 | IN | Address write channel ready |
| m_axi_awuser | 1 | OUT | Address write channel user defined |
| m_axi_awregion | 4 | OUT | Address write channel multiple region |
| m_axi_wdata | AXI_DATA_W | OUT | Write channel data |
| m_axi_wstrb | AXI_DATA_W/8 | OUT | Write channel write strobe |
| m_axi_wlast | 1 | OUT | Write channel last word flag |
| m_axi_wvalid | 1 | OUT | Write channel valid |
| m_axi_wready | 1 | IN | Write channel ready |
| m_axi_wuser | 1 | OUT | Write channel user defined |
| m_axi_bid | AXI_ID_W | IN | Write response channel ID |
| m_axi_bresp | 2 | IN | Write response channel response |
| m_axi_bvalid | 1 | IN | Write response channel valid |
| m_axi_bready | 1 | OUT | Write response channel ready |
| m_axi_buser | 1 | IN | Write response channel user defined |
| m_axi_arid | AXI_ID_W | OUT | Address read channel ID |
| m_axi_araddr | AXI_ADDR_W | OUT | Address read channel address |
| m_axi_arlen | AXI_LEN_W | OUT | Address read channel burst lengh |
| m_axi_arsize | 3 | OUT | Address read channel burst size |
| m_axi_arburst | 2 | OUT | Address read channel burst type |
| m_axi_arlock | 2 | OUT | Address read channel lock type |
| m_axi_arcache | 4 | OUT | Address read channel memory type |
| m_axi_arprot | 3 | OUT | Address read channel protection type |
| m_axi_arqos | 4 | OUT | Address read channel quality of service |
| m_axi_arvalid | 1 | OUT | Address read channel valid |
| m_axi_arready | 1 | IN | Address read channel ready |
| m_axi_aruser | 1 | OUT | Address read channel user defined |
| m_axi_arregion | 4 | OUT | Address read channel multiple region |
| m_axi_rdata | AXI_DATA_W | IN | Read channel data |
| m_axi_rstrb | AXI_DATA_W/8 | IN | Read channel write strobe |
| m_axi_rlast | 1 | IN | Read channel last word flag |
| m_axi_rvalid | 1 | IN | Read channel valid |
| m_axi_rready | 1 | OUT | Read channel ready |
| m_axi_ruser | 1 | IN | Read channel user defined |
Read Channel Ctrl****
读通道控制器从更高一级Cache或主存中获取cache line,并在替换cache line时将其写入当前Cache。
F igure 5 - 3 - 1 . Back_end Read FSM****
Write Channel Ctrl
写通道控制器从Write-Through-Buffer读取数据,并将数据写入主存。数据传输后,通过写响应通道检查数据传输是否成功:如果bresp的值不是OKAY,表示数据传输不成功,将再次传输数据。
Cache Structure****
cache容量较小,所以数据需要按照一定的规则从主存映射到cache。一般把主存和cache分割成一定大小的块,这个块在主存中称为data block,在cache中称为cache line。举个例子,块大小为1024Bytes,那么data block和cache line都是1024Bytes
cache的大小称为cache size,代表cache可以缓存的最大数据量。cache line的大小是cache line size。例如一个64 Bytes大小的cache。如果我们将64 Bytes平均分成64块,那么cache line size就是1Byte,总共64个cache line。如果我们将64 Bytes平均分成8块,那么cache line size就是8Bytes,总共8个cache line。cache line size是cache和主存之间进行数据传输的最小单位。
处理器通过主存地址访问cache。处理器与cache之间通过字进行数据交换,cache与主存之间通过块进行数据交换,所以需要知道块在cache中的地址,以及块中包含多少个字,即块内偏移地址。在cache中块地址又可以进一步划分为Tag段和Index段。Tag段用来判断数据是否在cache当中,Index段指示在cache的哪个位置去读写数据。
F igure 6 - 1 - 1 . cache a ddress composition
此外,cache line的组成还包括Valid段和Dirty段。Valid段指示cache中的数据是否有效,Dirty段指示主存中的数据是否为最新。
当把主存和cache分割好之后,我们就可以把data block放到cache line中,而这个“放”的规则,即主存与cache地址映射常见的映射方式有:全相联映射、直接映射和组相联映射。本IP可实现直接映射和组相联映射,下面将对这两个映射方式进行详细介绍。
我们假设下面的讲解都是针对64 Bytes大小的cache,并且cache line大小是8Bytes,共有8个cache line。
Direct Mapping****
直接映射采用“取模”的方式进行一对一映射。例如,如果cache中共有8个cache line,那么0、8、16、24...号data block会被映射到0号cache line中,同理1、9、17....号data block会被映射到1号cache line中,具体可以参考下面的关系图。
F igure 6 - 1 - 2 . Direct Mapping diagram
直接映射等同于单路组相联映射。处理器访问cache的地址会被分为三个部分:Tag、Index以及Block Offset,结构如下图所示。其中,Index用来指定选中哪一个cache line,Tag用来与cache line的Tag作比较以生成hit信号,而Offset则从选择的cache line中选中部分数据进行输出。cache line中还有一个有效位(Valid),用来标记这个cache line是否保存着有效的数据,只有该位为1才表明cache line有效,否则cache miss。
Set Associative Mapping****
直接映射中主存的每一个data block都与一个确定的cache line进行映射,那么当程序连续读取0、8、0、8号data block的数据时,因为只有一个cache line可供映射,当第二次读取0号block时,第一次读到cache中的0号data block已经被替换出去了,这时候又会产生miss,miss会极大地影响执行效率。组相联映射解决了直接映射中Index相同的数据只能放在一个cache line的问题。
组相联映射cache使用cache set的概念,一个cache set包含多个cache line,这些cache line的Index相同。当一个cache set中的某个cache line被占用,而另一个cache line空闲时,就不必替换掉已有的数据,而是使用空闲的槽位,这样就大大降低了缺失率。一个cache set所包含的cache line个数就被称为这个cache的相联度。例如,若一个cache set包含2个cache line,则称为2路组相联cache,结构如下图所示:
F igure 6 - 1 - 3 . Set Associative Mapping structure
上图中可以看到,cache被分成了两个存储区域。其中,一个存储区域叫做一“路”。
由于需要从多个cache line中选择一个匹配的结果,这种实现方式相对于直接映射结构的cache而言,延迟会更大,有时候甚至需要将其访问过程流水化,以减少对处理器频率的影响,但这样会导致处理器load指令的latency增大,一定程度上影响了处理器的执行效率。这种方式的优点在于,它可以显著地减少cache缺失发生的频率。
在实际实现中,Tag和Data是分开存储的,分别叫做Tag SRAM和Data SRAM。基于这种实现,可以采用并行访问(同时访问Tag SRAM和Data SRAM)或串行访问(先访问Tag SRAM再访问Data SRAM)方法。
下图是并行访问实现方式。Tag SRAM和Data SRAM同时译码,同时读取Tag和Data,并根据Tag比较的结果来选择一组Data输出,Aligner是字节选择器。这里关键的地方在于,看起来就像把cache set中的两路cache line横向拼接起来,然后根据Index的译码结果选中某一行,这一行包含两个cache line中data。
F igure 6 - 1 - 4 . p arallel implementation
下图是串行访问实现方式。相比于并行,这里的关键地方是我们把两路cache line纵向拼接了,这样cache line的数量翻倍,通过Tag比较和Index译码的综合结果,我们最终只会选中一个cache line,选中的cache line中的数据直接送往Aligner。这样的工作过程有明显的串行特征,即首先比较Tag,然后才选中某一cache line。
F igure 6 - 1 - 5 . serial implementation
比较串行和并行实现,并行实现因为比串行多一个多路选择器,工作时间会变长,对应的时钟频率会下降,而且每次同时选中多个cache line,功耗较大;而串行实现在用流水线来实现cache时会明显增加所需时钟周期数(多一个时钟周期)。
Cache Allocation Policy****
cache的分配策略是指在什么情况下应该为数据分配cache line。cache分配策略分为读和写两种情况。
Read Allocation****
当CPU读数据时,发生cache缺失,这种情况下都会分配一个cache line存储从主存读取的数据。默认情况下,cache都支持读分配。
Write Allocation****
当CPU写数据发生cache缺失时,才会考虑写分配策略。不支持写分配的情况下,写指令只会更新主存数据,然后就结束了。当支持写分配时,首先从主存中加载数据到cache line(相当于先做个读分配动作),然后会更新cache line中的数据。
Cache U pdate P olicy****
cache更新策略是指当发生cache命中时,写操作应该如何更新cache数据。cache更新策略分成两种:写Write Through和Write Back。Write Through在把数据写到Cache的同时,也将数据写到更高一级cache中。Write Back是将数据写到cache当中,但并不立即更新到更高一级cache。
一般情况下,Write Through和写不分配组合,Write Back和写分配组合。
采用Write Back写策略时,速度较快,但因只改写cache,cache line和主存中的数据不再一致,便产生了“一致性”问题。如果有别的core来访问主存中对应的data block,它将会读到错误的数据。另外,在cache line被替换出去的时候,数据应该被写进主存,这就要求能够辨别哪些cache line是被改写过的,因此需增加一个Dirty位,当一个被标记为Dirty的cache line被替换出去,其内容需要被写入主存。
Write Through****
当写策略是Write Through时,本IP的读写流程如下所示:
Write Back****
当写策略是Write Back时,本IP的读写流程如下所示:
Cache Replacement P olicy
不论是读数还是写数,一旦发生miss,就可能需要替换cache line。读miss时需要从主存调入data block,而这个block可能需要顶替某个cache line。写的时候如果使用“写分配”,那也需要从主存调入data block。对于直接映射,任意data block只有唯一的cache line可用,对于组相联映射或全相联映射,这时候需要替换算法来决定顶替哪一个cache line。本IP可实现LRU(Least Recently Used)、PMRU(Pseudo Most Recently Used)和PLRU(Pseudo Least Recently Used)_tree这三种替换策略。
LRU****
LRU的基本思想是选择最近一段时间使用次数最少的cache line进行替换,因此需要对一个cache set中的每一个cache line的使用情况进行跟踪,实现方法可以是为每一个cache line都设置一个“Age”。
如果是2路cache(即每一个cache set只有2个cache line),那么只需要一位“Age”。当一个cache line被使用,那么它的年龄为1,另一个cache line的年龄为0。如果是多路cache,那么就需要多位“Age”,当一个cache line被使用,那么它对应的年龄就应该被设置为最大,其他cache line的年龄按照之前的顺序排在它之后。替换的时候总是替换年龄最小的那个cache line。
本IP中,组相联映射的way的数量由N_WAYS给定,LRU替换算法需要为每一set提供一个N_WAYS*log2(N_WAYS)位的年龄位mru[i],最近最少使用的way的mru[i]等于0,最近最多使用的way的mru[i]等于N_WAYS-1。mru[i]的更新如下图所示。way的选择遵循以下公式:
way_select [i] = !OR(mru[i])
Clean/Invalid****
clean指检查cacheline的dirty位,并将dirty位为1的所有cacheline写回主存,之后将dirty位全置0。通过这种方式可以让cacheline中的数据和主存中的数据一致。该指令仅仅适用于write_back类型的cache。
invalid指将cacheline的valid位均置0,这时候并不需要真的清除相应位置的cacheline数据,但后续读写均会走miss流程。
(flush=clean+invalid)