引言
为CPU提供足够的,稳定的指令流和数据流是计算机体系结构设计中两个永恒的话题。为了给CPU提供指令流,需要设计分支预测机构,为了给CPU提供数据流,就需要设计cache了。其实,无论是insn还是data,都需要访问存储器,所以从这个角度来说,cache需要承担更重要的角色。
本小节我们就分析一下or1200的cache部分的实现。
1,cache产生原因
还是那句话,研究一个东西,首先要了解其来龙去脉,cache也不例外。
cache的出现是为了解决memory wall问题。由于cpu的频率越来越高,处理能力越来越大,但存储系统虽有一定发展,但还是和CPU的距离越来越大。这样就会出现“茶壶里倒饺子”的情况,就是所谓的存储墙问题。cache,正是为了解决这个问题而出现的。
2,cache基础
关于cache,我们需要先了解cache的映射方式,写策略,替换策略,cache的优化技术,等等相关内容。这些内容,我们之前都已介绍过了,这里不再赘述,如有疑问,请参考:http://blog.csdn.net/rill_zhen/article/details/9491095
3,cache工作机制
1>基本工作过程
在分析or1200的cache的具体实现之前,我们有必要先了解cache的一般工作机制。为了清晰的展示这个过程,我假设了一个例子,这个例子是MMU模块分析时,那个例子的延伸。
在分析or1200的MMU时,我们假设了一个例子,那个示例中,MMU将变量test的虚拟地址(0x2008),转换成了物理地址(0x1006008)。
cpu访问内存,虚实地址转换,是其中的第一步,在完成虚实转换之后,并不是直接用这个地址访问外部的SDRAM,而是MMU先将物理地址发送到cache,如果cache hit则直接ack cpu,如果cache miss则才需要访问下一级cache或外部SDRAM。
2>直接映射cache的工作机制
上面我们介绍了cache的大致工作流程,但是,cache的具体工作细节是怎样的呢?
得到test的物理地址之后是如何运作的呢,下面,我们就以直接映射的,大小为8K,line数目为512,line宽度为16-Bytes的一个cache,来说明,如下图所示:
通过这幅图,我们可以很清楚的看到其工作细节。
说明:
a,这个cache的映射方式是direct mapped。
b,cache的总容量是8K,也正好就是一个内存页。
c,整个cache有512个cache line,或者叫cache entry。
d,每个cache line缓存16个字节的数据。
e,由于是直接映射,所以不存在什么替换算法,哪个line出现cache miss就替换哪个。
f,写策略,write through和write back两种。
g,由于cache一般是对软件编程模型透明的,所以很少需要和软件交互,只需要最基本的控制,比如,需要把那个通道lock啊,cache flush啊,如果采用LRU替换算法,及时更新LRU值啊,等等。这一点和MMU大不相同,MMU需要软件的大量的干预和控制。
h,简单介绍一下工作机制:
首先,cache将虚拟地址的index域进行取模运算(%),具体和那个值取模,就看cache line的数量和缓存的数据大小。本例子中cacheline数量是512,缓存数量是16B,所以,需要将index分成cache line index(定位到哪一行),和行内偏移(定位到这一行的哪一个字节)。
cache根据cache line index定位到cache的具体一行,判断这一行的valid标志,如果有效,在将这一行的tag和MMU产生的PPN进行比较(因为一个cache line可能会对应多个内存地址)。如果tag和PPN匹配,那么说明cache hit,如果两个判断条件有一个不满足,说明cache miss,这时,cache会burst access(突发访问,本例子是叠4,每次4B,正好16B),更新这一个cache line。
i,cache的操作
刷新:cache将valid置0即可。
锁定:加入有某个程序运行时间很长,为了防止其他程序在出现cache miss时将这个程序的cache line刷新,可以将这个程序使用的cache line 锁定。具体锁定方式可以是通道锁定,也可以是某一行锁定(将整个cache分成若干组,每个组有若干行,一个组就叫一个通道(way))。
3>全相连映射cache的工作机制
上面我们介绍了直接映射cache的工作机制,其他两种映射方式的cache也大体相同,不同的地方是cache line搜索方法,替换策略,写策略不同。
全相连映射cache的工作机制,如下图所示:
4>组相连映射cache的工作机制
介于直接映射和全相连映射之间,不再赘述。
4,or1200的cache系统分析
了解了cache的工作机制之后,再分析or1200的cache的具体实现就相对容易一些,由于cache只是内存的一个子集,没有独立的编程空间,所以与软件的交互比较少,分析起来就更简单一些。
1>or1200的cache的工作机制
or1200的cache采用直接映射方式,大小是8K,共512个entry,每个line缓存16个字节,每个line由1-bit标志位,19-bit tag和16*8-bit数据组成。
上面我们已经详细说明了这种cache的工作机制,or1200的cache也不例外。
2>or1200的cache组成
or1200的cache,由qmem模块组成一级cache,dcache/icache组成二级cache,sb模块组成数据的三级cache。
下面是整个ordb2a开饭板的存储系统的框图,从中,我们可以清晰的看出整个系统的存储子系统的数据通路。
3>qmem模块分析
1》整体分析
qmem模块的实质是一块小的RAM,在or1200_define.v中,对qmem有如下描述,从中我们可以知道qmem的作用,意义,容量等信息。
/
//
// Quick Embedded Memory (QMEM)
//
//
// Quick Embedded Memory
//
// Instantiation of dedicated insn/data memory (RAM or ROM).
// Insn fetch has effective throughput 1insn / clock cycle.
// Data load takes two clock cycles / access, data store
// takes 1 clock cycle / access (if there is no insn fetch)).
// Memory instantiation is shared between insn and data,
// meaning if insn fetch are performed, data load/store
// performance will be lower.
//
// Main reason for QMEM is to put some time critical functions
// into this memory and to have predictable and fast access
// to these functions. (soft fpu, context switch, exception
// handlers, stack, etc)
//
// It makes design a bit bigger and slower. QMEM sits behind
// IMMU/DMMU so all addresses are physical (so the MMUs can be
// used with QMEM and QMEM is seen by the CPU just like any other
// memory in the system). IC/DC are sitting behind QMEM so the
// whole design timing might be worse with QMEM implemented.
//
//`define OR1200_QMEM_IMPLEMENTED
//
// Base address and mask of QMEM
//
// Base address defines first address of QMEM. Mask defines
// QMEM range in address space. Actual size of QMEM is however
// determined with instantiated RAM/ROM. However bigger
// mask will reserve more address space for QMEM, but also
// make design faster, while more tight mask will take
// less address space but also make design slower. If
// instantiated RAM/ROM is smaller than space reserved with
// the mask, instatiated RAM/ROM will also be shadowed
// at higher addresses in reserved space.
//
`define OR1200_QMEM_IADDR 32'h0080_0000
`define OR1200_QMEM_IMASK 32'hfff0_0000 // Max QMEM size 1MB
`define OR1200_QMEM_DADDR 32'h0080_0000
`define OR1200_QMEM_DMASK 32'hfff0_0000 // Max QMEM size 1MB
//
// QMEM interface byte-select capability
//
// To enable qmem_sel* ports, define this macro.
//
//`define OR1200_QMEM_BSEL
//
// QMEM interface acknowledge
//
// To enable qmem_ack port, define this macro.
//
//`define OR1200_QMEM_ACK
从上面我们可以看出,qmem是总线上的一个buffer,但对于cpu内核来说,qmem不是透明的,是可见的。
当cpu从读cache的时候,地址线对于cache和qmem都是有效的,但是qmem要比cache响应快。
当cpu写cache的时候,如果在qmem的地址范围内,qmem也会更新,所以不会出错。
咱们举一个例子。
假如你是qmem,我是cache,还有路人甲是cpu。
你和我负责提供旅游路线咨询,咱们使用同一个电话号码的两个分机,如果有人打电话,咱们的分机会同时响铃。
你手上只有北京的地图,我手上有全国地图,路人甲如果想去一个地方旅游,打了咱们的那个电话(read cache),咱们都会拿起电话,如果路人甲想去北京旅游,由于你的地图小,反应快,这样,你就会把路线信息告诉他(qmem hit)。如果路人甲想去上海旅游,上海不在你的地图上(qmem miss),那么就由我来回答,但时间会长一点(而不是你再问我,还由你来回答)。
如果路人甲从北京旅游回来打咱们的电话说,颐和园正在维修,不对外开放了(write cache),你和我都会听到这个信息,所以你的北京地图和我的全国地图都会更新。
所以,如果有路人乙再去北京旅游,直接从你那得到消息是不会出错的。
既然qmem对cpu是可见的,那么qmem就和外部的SDRAM在逻辑上是平等的。所不同的是qmem容量更小,访问速度更快(只需一个clock),还有一个重要的区别是qmem miss不会引起异常,但是如果SDRAM miss就会引起异常。
既然qmem对cpu是可见的,那么qmem的使用是由软件程序员控制的。软件程序员必须知道qmem的存在。
既然qmem也是编程空间的一部分,那么qmem就和一般的SDRAM一样使用了,所以,也就没有reload操作了。
关于qmem,我们需要注意一下几点:
a,qmem的地址空间有多大,如下代码所示: