overview

164 阅读21分钟

Overview

Cache主要用于提供高速存储访问,是利用数据的时间局部性和空间局部性而设计的小存储单元。即用一块更小更快的存储设备作为更大更慢的存储设备的缓冲区,从而提高数据访问速度。本文实现了一种高性能可配置的Cache,采用独立模块化设计,前端接口支持AHB4,后端接口支持AXI4。

System Block Diagram

image.png 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_Windex字段 width,cache lines总数为N_WAYS*2LINE_OFF_W
WORD_OFF_Woffset字段width,每个cache line数据位宽是FE_ADDR_W*WORD_OFF_W
WTBUF_DEPTH_WWrite-Through-Buffer FIFO深度
REP_POLICYLRU (0); PLRU_mru (1); PLRU_tree (2)
WRITE_POL写策略,write-through (0), write-back (1)
AXI_ID_WAXI_ID数据位宽
AXI_ADDR_WAXI读写主存地址位宽
AXI_DATA_WAXI读写主存数据位宽
AXI_LEN_WAXI突发长度位宽

 

Interface****Width****IN /OUT****Description****
clk1IN系统时钟
rst_n1IN系统复位
idle1OUTidle状态指示信号
haddrFE_ADDR_WINWRITE AHB address
hburst3INWRITE AHB burst type
hprot4INWRITE AHB transfer protection ctrl
hsize3INWRITE AHB transfer size
htrans2INWRITE AHB transfer type
hwdataFE_DATA_WINWRITE AHB write data
hwrite1INWRITE AHB transfer direction
hrdataFE_DATA_WOUTWRITE AHB read data
hready1OUTWRITE AHB transfer ready
hresp1OUTWRITE AHB transfer error
m_axi_awidAXI_ID_WOUTAddress write channel ID
m_axi_awaddrAXI_ADDR_WOUTAddress write channel address
m_axi_awlenAXI_LEN_WOUTAddress write channel burst lengh
m_axi_awsize3OUTAddress write channel burst size
m_axi_awburst2OUTAddress write channel burst type
m_axi_awlock2OUTAddress write channel lock type
m_axi_awcache4OUTAddress write channel memory type
m_axi_awprot3OUTAddress write channel protection type
m_axi_awqos4OUTAddress write channel quality of service
m_axi_awvalid1OUTAddress write channel valid
m_axi_awready1INAddress write channel ready
m_axi_awuser1OUTAddress write channel user defined
m_axi_awregion4OUTAddress write channel multiple region
m_axi_wdataAXI_DATA_WOUTWrite channel data
m_axi_wstrbAXI_DATA_W/8OUTWrite channel write strobe
m_axi_wlast1OUTWrite channel last word flag
m_axi_wvalid1OUTWrite channel valid
m_axi_wready1INWrite channel ready
m_axi_wuser1OUTWrite channel user defined
m_axi_bidAXI_ID_WINWrite response channel ID
m_axi_bresp2INWrite response channel response
m_axi_bvalid1INWrite response channel valid
m_axi_bready1OUTWrite response channel ready
m_axi_buser1INWrite response channel user defined
m_axi_aridAXI_ID_WOUTAddress read channel ID
m_axi_araddrAXI_ADDR_WOUTAddress read channel address
m_axi_arlenAXI_LEN_WOUTAddress read channel burst lengh
m_axi_arsize3OUTAddress read channel burst size
m_axi_arburst2OUTAddress read channel burst type
m_axi_arlock2OUTAddress read channel lock type
m_axi_arcache4OUTAddress read channel memory type
m_axi_arprot3OUTAddress read channel protection type
m_axi_arqos4OUTAddress read channel quality of service
m_axi_arvalid1OUTAddress read channel valid
m_axi_arready1INAddress read channel ready
m_axi_aruser1OUTAddress read channel user defined
m_axi_arregion4OUTAddress read channel multiple region
m_axi_rdataAXI_DATA_WINRead channel data
m_axi_rstrbAXI_DATA_W/8INRead channel write strobe
m_axi_rlast1INRead channel last word flag
m_axi_rvalid1INRead channel valid
m_axi_rready1OUTRead channel ready
m_axi_ruser1INRead channel user defined
invalidate1INtotal cacheline invalid信号
clean1INtotal cacheline clean信号
cnt_en1INtrans/hit/miss计数使能
cnt_clr1INtrans/hit/miss计数清零
write_hit1OUT当前haddr write hit标志信号
write_miss1OUT当前haddr write miss标志信号
read_hit1OUT当前haddr read hit标志信号
read_miss1OUT当前haddr read miss标志信号
write_hit_cntFE_DATA_WOUTwrite hit计数
write_miss_cntFE_DATA_WOUTwrite miss计数
read_hit_cntFE_DATA_WOUTread hit计数
read_miss_cntFE_DATA_WOUTread miss计数
hit_cntFE_DATA_WOUTread和write hit计数
miss_cntFE_DATA_WOUTread和write miss计数
trans_cntFE_DATA_WOUTtrans总计数
cache_ecc_en1INdata memory ECC使能
cache_one_ecc_err1OUTdata memory 单个错误标志
cache_two_ecc_err1OUTdata 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等替换策略。

image.png

Cache memory interface

Interface****Width****IN /OUT****Description****
clk1IN时钟
reset1IN复位
idle1OUTidle状态指示信号
valid1IN读写请求有效
addrFE_ADDR_WINnative port 读写地址
wstrbFE_NBYTESINnative port 写选通
rdataFE_DATA_WOUTnative port 读数据
ready1OUTnative port ready
valid_reg1IN由Front_end输入,数据有效标志,用来store data
addr_regFE_ADDR_W-FE_BYTE_WIN由Front_end输入,数据地址,用来store data
wdata_regFE_DATA_WIN由Front_end输入,写数据,用来store data
wstrb_regFE_NBYTESIN由Front_end输入,写选通,用来store data
write_valid1OUT输出至Back_end,写有效
write_addrFE_ADDR_W-FE_BYTE_W-WRITE_POL*WORD_OFF_WOUT输出至Back_end,写地址
write_wdataFE_DATA_W+WRITE_POL*(FE_DATA_W*(2**WORD_OFF_W)-FE_DATA_W)OUT输出至Back_end,写数据
write_wstrbFE_NBYTESOUT输出至Back_end,写选通
write_ready1IN由Back_end输入,写通道处于空闲状态
replace_valid1OUT输出至Back_end,替换有效标志
replace_addrFE_ADDR_W-BE_BYTE_W-LINE2MEM_WOUT输出至Back_end,替换数据地址
replace1IN由Back_end输入,数据替换完成
read_valid1IN由Back_end输入,读取数据有效
read_addrLINE2MEM_WIN由Back_end输入,axi read burst中每次读取的位宽是BE_DATA_W的数据在需替换cache line中的offset(arlen = 2^LINE2MEM_W-1)
read_rdataBE_DATA_WIN由Back_end输入,读取数据
invalidate1INtotal cacheline invalid信号
clean1INtotal cacheline clean信号
cnt_en1INtrans/hit/miss计数使能
cnt_clr1INtrans/hit/miss计数清零
write_hit1OUT当前haddr write hit标志信号
write_miss1OUT当前haddr write miss标志信号
read_hit1OUT当前haddr read hit标志信号
read_miss1OUT当前haddr read miss标志信号
write_hit_cntFE_DATA_WOUTwrite hit计数
write_miss_cntFE_DATA_WOUTwrite miss计数
read_hit_cntFE_DATA_WOUTread hit计数
read_miss_cntFE_DATA_WOUTread miss计数
hit_cntFE_DATA_WOUTread和write hit计数
miss_cntFE_DATA_WOUTread和write miss计数
trans_cntFE_DATA_WOUTtrans总计数
cache_ecc_en1INdata memory ECC使能
cache_one_ecc_err1OUTdata memory 单个错误标志
cache_two_ecc_err1OUTdata memory 两个错误标志
wtbuf_full1OUTwrite through buffer full标志信号
wtbuf_empty1OUTwrite through buffer empty标志信号
buffer_full_pre1OUTwrite through buffer pre full,提前一拍
buffer_wen1INwrite 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****
clk1IN时钟
reset1IN复位
write_valid1IN输出至Back_end,写有效
write_addrFE_ADDR_W-FE_BYTE_W-WRITE_POL*WORD_OFF_WIN由Cache_Memory输入,写地址
write_wdataFE_DATA_W+WRITE_POL*(FE_DATA_W*(2**WORD_OFF_W)-FE_DATA_W)IN输出至Back_end,写数据
write_wstrbFE_NBYTESIN输出至Back_end,写选通
write_ready1OUT由Back_end输入,写通道处于空闲状态
replace_valid1IN输出至Back_end,替换有效标志
replace_addrFE_ADDR_W-BE_BYTE_W-LINE2MEM_WIN输出至Back_end,替换数据地址
replace1OUT由Back_end输入,数据替换完成
read_valid1OUT由Back_end输入,读取数据有效
read_addrLINE2MEM_WOUT由Back_end输入,axi read burst中每次读取的位宽是BE_DATA_W的数据在需替换cache line中的offset(arlen = 2^LINE2MEM_W-1)
read_rdataBE_DATA_WOUT由Back_end输入,读取数据
m_axi_awidAXI_ID_WOUTAddress write channel ID
m_axi_awaddrAXI_ADDR_WOUTAddress write channel address
m_axi_awlenAXI_LEN_WOUTAddress write channel burst lengh
m_axi_awsize3OUTAddress write channel burst size
m_axi_awburst2OUTAddress write channel burst type
m_axi_awlock2OUTAddress write channel lock type
m_axi_awcache4OUTAddress write channel memory type
m_axi_awprot3OUTAddress write channel protection type
m_axi_awqos4OUTAddress write channel quality of service
m_axi_awvalid1OUTAddress write channel valid
m_axi_awready1INAddress write channel ready
m_axi_awuser1OUTAddress write channel user defined
m_axi_awregion4OUTAddress write channel multiple region
m_axi_wdataAXI_DATA_WOUTWrite channel data
m_axi_wstrbAXI_DATA_W/8OUTWrite channel write strobe
m_axi_wlast1OUTWrite channel last word flag
m_axi_wvalid1OUTWrite channel valid
m_axi_wready1INWrite channel ready
m_axi_wuser1OUTWrite channel user defined
m_axi_bidAXI_ID_WINWrite response channel ID
m_axi_bresp2INWrite response channel response
m_axi_bvalid1INWrite response channel valid
m_axi_bready1OUTWrite response channel ready
m_axi_buser1INWrite response channel user defined
m_axi_aridAXI_ID_WOUTAddress read channel ID
m_axi_araddrAXI_ADDR_WOUTAddress read channel address
m_axi_arlenAXI_LEN_WOUTAddress read channel burst lengh
m_axi_arsize3OUTAddress read channel burst size
m_axi_arburst2OUTAddress read channel burst type
m_axi_arlock2OUTAddress read channel lock type
m_axi_arcache4OUTAddress read channel memory type
m_axi_arprot3OUTAddress read channel protection type
m_axi_arqos4OUTAddress read channel quality of service
m_axi_arvalid1OUTAddress read channel valid
m_axi_arready1INAddress read channel ready
m_axi_aruser1OUTAddress read channel user defined
m_axi_arregion4OUTAddress read channel multiple region
m_axi_rdataAXI_DATA_WINRead channel data
m_axi_rstrbAXI_DATA_W/8INRead channel write strobe
m_axi_rlast1INRead channel last word flag
m_axi_rvalid1INRead channel valid
m_axi_rready1OUTRead channel ready
m_axi_ruser1INRead channel user defined

Read Channel Ctrl****

读通道控制器从更高一级Cache或主存中获取cache line,并在替换cache line时将其写入当前Cache。

image.png

F igure 5 - 3 - 1 . Back_end Read FSM****

Write Channel Ctrl

写通道控制器从Write-Through-Buffer读取数据,并将数据写入主存。数据传输后,通过写响应通道检查数据传输是否成功:如果bresp的值不是OKAY,表示数据传输不成功,将再次传输数据。

image.png

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的哪个位置去读写数据。

image.png 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中,具体可以参考下面的关系图。

image.png 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。

image.png

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,结构如下图所示:

image.png 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。

image.png F igure 6 - 1 - 4 . p arallel implementation

下图是串行访问实现方式。相比于并行,这里的关键地方是我们把两路cache line纵向拼接了,这样cache line的数量翻倍,通过Tag比较和Index译码的综合结果,我们最终只会选中一个cache line,选中的cache line中的数据直接送往Aligner。这样的工作过程有明显的串行特征,即首先比较Tag,然后才选中某一cache line。

image.png 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的读写流程如下所示:

image.png

image.png

Write Back****

当写策略是Write Back时,本IP的读写流程如下所示:

image.png

image.png

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。

image.png 本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])

image.png

Clean/Invalid****

clean指检查cacheline的dirty位,并将dirty位为1的所有cacheline写回主存,之后将dirty位全置0。通过这种方式可以让cacheline中的数据和主存中的数据一致。该指令仅仅适用于write_back类型的cache。

invalid指将cacheline的valid位均置0,这时候并不需要真的清除相应位置的cacheline数据,但后续读写均会走miss流程。

(flush=clean+invalid)