一、存储器架构概述
1.1 处理器缓存
谈及处理器的存储器子系统,讨论的最多的莫过于缓存(Cache)。缓存几乎可以认为是处理器微架构中最复杂的部分,常见的缓存基础知识如下:
- 缓存的映射类型。常见类型如直接映射,全相联映射,组相联映射等。
- 缓存的写回策略。常见类型如写穿通,写分配等。
- 缓存使用物理地址还是虚拟地址索引。常见类型如PIPT,VIPT等。
- 缓存的标签(Tag)和数据(Data)的组织顺序。常见的如串行组织,并行组织等。
- 多级缓存的组织和管理。
- 在多核架构下的缓存一致性。
众多极低功耗的处理器其实并没有配备缓存,主要是出于如下几个方面的原因:
(1)无法保证实时性
- 这是缓存不被使用的最主要原因。缓存是一种缓存机制,利用软件程序的时间局部性和空间局部性,将空间巨大的存储器动态映射到容量有限的缓存中,可以将访问存储器的平均延迟降低到最小。
- 由于缓存的容量是有限的,因此访问缓存存在着相当大的不确定性。一旦缓存不命中(Cache-Miss),则需要从外部的存储器中存取数据,造成较长的延迟。在对实时性要求高的场景中,处理器的反应速度必须有最可靠的实时性。如果使用了缓存,则无法保证这一点。
- 大多数极低功耗低处理器应用的场景都应用于实时性较高的场景,因此更加倾向于使用延迟确定的ITCM或者DTCM。
(2)软件规模小
- 大多数极低功耗处理器均应用于深嵌入式领域。此领域中的软件代码规模一般较小,所需要的数据段也较小,使用几十KB的片上SRAM或者ITCM、DTCM便可以满足其需求,因此缓存能够缓存空间巨大的存储器数据的优点在此变得无用武之地了。
(3)面积功耗大
- 缓存的设计难度比ITCM和DTCM要大很多,消耗的面积资源和带来的功耗损失也更大。而极低功耗处理器更加追求小面积和能效比,因此更倾向于使用ITCM和DTCM。
基于以上几个原因,目前主流的极低功耗处理器其实都没有使用缓存。
1.2 处理器存储器
虽然处理器不一定需要缓存,但是处理器是一定需要存储器的。
下图为冯诺依曼提出的计算机体系结构模型,计算机必须具备五大组成设备:输入设备,输出设备,存储器,运算器和控制器。其中,运算器和控制器可以归于处理器核的范畴,其运行的指令和所需要的数据都必须来自存储器。
熟悉计算机体系结构的读者一定知道处理器访问存储器的策略,在理论上存在着冯诺依曼结构和哈佛结构。
(1)冯诺依曼结构也称普林斯顿结构,是一种将指令存储器和数据存储器合并在一起的存储器结构。程序的指令存储地址和数据存储地址指向同一个存储器的不同物理地址。
(2)哈佛结构是一种将指令存储器和数据存储器分开的存储器架构。如下图所示。它的主要特点如下。
- 将程序和数据存储在不同的存储空间中,即程序存储器和数据存储器是两个独立的存储器,每个存储器独立编址,独立访问。
- 于两个存储器相对应的是两条独立的指令总线和数据总线。这种分离的总线使得处理器可以在一个周期内同时获得指令字和操作数,从而提高了执行速度和数据的吞吐率。
- 由于指令和数据存储在分开的物理空间中,因此取指和执行能完全并行。
而在实际的现代处理器设计中,冯诺依曼结构和哈佛结构的概念界限已经变得越来越微妙,而且模糊,具体阐述如下。
- 从软件程序的角度来看,系统往往只有一套地址空间,程序的指令存储地址和数据存储地址指向同一套地址空间的不同物理地址,因此这符合冯诺依曼体系结构的准则。
- 从硬件实现角度来看,现代处理器设计往往会配备专用的一级指令缓存和一级数据缓存,或者专用的一级指令存储器和一级数据存储器,因此符合哈佛结构的标准。
- 即便是对于一级指令存储器,有的处理器也可以存储数据,供存储器读写指令访问。因此这也变成了一种冯诺依曼体系架构。
- 现代处理器往往会配备指令和数据共享的二级缓存,或者共享的二级存储器。在二级存储器中,程序的指令存储地址和数据存储地址指向同一套地址空间的不同物理地址,并且共享读写访问通道,因此符合冯诺依曼结构的准则。
综上原因,可以看出冯诺依曼结构和哈佛结构并不是一种非此即彼的选择,无需按照两种架构严格区分现代的处理器。只需明白其优缺点。
1.3 ITCM和DTCM
处理器未必需要缓存,但是需要存储器,作为典型代表,Cortex-M3和M4处理器核配备了指令紧耦合存储器(Instruction Tightly Coupled Memory,ITCM)和数据紧耦合存储器(Data Tightly Coupled Memory,DTCM),相比于缓存而言更加适合嵌入式低功耗处理器,原因如下:
(1)能够保证实时性
ITCM和DTCM被映射到不同的地址区间,处理器的访问使用明确的地址映射的方式访问ITCM和DTCM。由于ITCM和DTCM并不是缓存机制,不存在着缓存不命中的情况,其访问的延迟是明确可知的,因此程序的执行过程能够得到明确的性能结果。在实时性要求高的场景,处理器的反应速度能够取得可靠的实时性。
(2)能够满足软件需求
大多数极低功耗处理器均应用于深嵌入式领域,此领域中的软件代码规模一般较小,所需要的数据段也较小,使用几十KB的ITCM和DTCM便可以满足其需求。
(3)面积功耗小
ITCM和DTCM设计很简单,面积和功耗更小。
二、RISC-V架构对于存储器访问指令的简化
具体对于存储器访问指令而言,RISC-V架构的如下特点可以大幅简化硬件实现。
- 仅支持小端格式
- 无地址自增自减模式
- 无“一次读多个数据”和“一次写多个数据”指令
2.1 仅支持小端模式
因为现在的主流应用是小端格式,RISC-V架构仅支持小端模式,而不支持大端格式,因此可以简化硬件的实现,无须做特别的数据转换。
2.2 无地址自增自减模式
很多RISC-V处理器都支持地址自增自减模式,这种自增或者自减的模式能够提高处理器访问连续存储器地址区间的性能,但同时也增加了处理器的硬件实现难度。由于RISC-V架构的存储器读和存储器写指令不支持地址自增自减的模式,因此可以很大程度上简化地址的生成逻辑。
2.3 无“一次读多个数据”和“一次写多个数据”指令
很多RISC架构定义了一次写多个寄存器到存储器中,或者一次从存储器中读出多个寄存器的指令,这样的好处是一条指令就可以完成很多事情。但是这种“一次读多个数据”和“一次写多个数据”指令的弊端是会让处理器的硬件设计非常复杂,增加硬件的开销,也可能损伤时序,无法提高处理器的主频。而RISC-V没有定义此类指令,使得硬件设计非常简单。
三、RISC-V架构的存储器相关指令
3.1 Load和Store指令
与所有的RISC处理器架构一样,RISC-V架构使用专用的存储器读(Load)指令和存储器写(Store)指令访问存储器,其他的普通指令无法访问存储器。
RISC-V架构定义了7条存储器读指令和存储器写指令,分别为LH,LHU,LB,LBU,LW,SB,SH,SW,用于支持以一个字节、半字、单字为单位的存储器读写操作。
3.2 Fence指令
RISC-V采用松散存储器模型(Relaxed Memory Model),松散存储器模型对于访问不同地址的存储器读写指令的执行顺序不作要求,除非使用明确的存储器屏蔽指令。
RISC-V架构定义了Fence和Fence.I两条存储器屏蔽指令,用于强行界定存储器访问的顺序,定义如下。
- 在程序中,如果添加了一条Fence指令,则Fence指令能够保证“在Fence之前所有指令造成的访存结果”必须比“在Fence之后所有指令造成的访存结果”先被观测到。
- 在程序中,如果添加了一条Fence.I指令,则“在Fence.I之后所有指令的取指令操作”一定能够观测到“在Fence.I之前所有指令造成的访存结果”。
3.3 “A”扩展指令
RISC-V架构定义了一种扩展指令子集(由A字母表示),主要用于支持在多线程情形下访问存储器的原子(Atomic)操作或者同步操作,其包括两类指令。
- Atomic Memory Operation(AMO)指令。
- Load-Reserved和Store-Conditional指令。