关于CPU对齐访问的基础知识:

现代计算机是以Byte 为主要单位存储数据的,CPU在访问数据寻址时用到的地址是指向各个数据的首个Byte的地址。

如:一个Char类型数据占用8个Bits,存放在一个Byte内,该Byte的地址即为该数据的存储地址;而一个int类型数据占用32个Bits,就需要存放在4个Bytes内,并以第1个Byte的地址作为该数据的存储地址。

以下转载自:https://yangwang.hk/?p=773

最近在研究CPU的微内核,遇到了一个问题:为何CPU要求内存访问对齐?

换句话说:CPU访问非对齐的内存时为何需要多次读取再拼接?

首先简单说一下何为内存对齐。

例如,当cpu需要取4个连续的字节时,若内存起始位置的地址可以被4整除,那么我们称其对齐访问。反之,则为未对齐访问。比如从地址0xf1取4字节就是非对齐(地址)访问。

简单的看来,对于一个数据总线宽度为32位的cpu,它一次拥有取出四字节数据的能力,理论上cpu应该是可以从任意的内存地址取四个连续字节的,而且是否对齐硬件的设计是相同的(如果内存和CPU都是字节组织的话,那么内存应当可以返回任意地址开始连续的四字节,CPU处理起来也没有任何差异)。

然而,很多cpu并不支持非对齐的内存访问,甚至在访问的时候会发生例外(例如arm架构的某些CPU)!而某些复杂指令集的cpu(比如x86架构),可以完成非对齐的内存访问,然而CPU也不是一次性读出四个字节,而是采取多次读取对齐的内存,然后进行数据拼接,从而实现非对齐数据访问的。如下图:

                                                       Cortex-M4存储模型(Memory Model)与MPU(Memory Protection Unit)

 

如果我们的数据存于内存的2-5中,在读取时实际上是先读取0-3,再读取4-7字节,再分别将2-3字节和4-5字节合并,最后得到所需的四字节数据。

那么为什么CPU不直接读取2-5,而是要么不提供支持,要么甚至不惜花大力气执行多次访问再拼接访问非对齐的内存呢(如此访问一则增加访问时间,二则增加电路的复杂性)?这背后一定有它的原因!

经过一番互联网搜索,但是在国内只能找到为什么写程序的时候要对齐的解释(因为CPU要么不支持,要么访问效率下降),然后是如何实现对齐。没有一篇文章从硬件原理上去分析为何访问非对齐内存如此麻烦。

最后我在神奇的StackOverflow网站上找到了相关的问题,以及合理的解答(看来并不是只有我一个人有类似的疑问)。

——————————————————————————分界线——————————————————————————

实际上,访问非对齐内存并没有我们想象的那么“简单”,例如,在一个常见的pc上,内存实际上是有多个内存芯片共同组成的(也就是内存条上那些黑色的内存颗粒)

为了提高访存的带宽,通常的做法是将地址分开,放到不同的芯片上。比如,第0-7bit在芯片0上储存,8-15bit在芯片2上组成,以此类推,如下图:

                                           Cortex-M4存储模型(Memory Model)与MPU(Memory Protection Unit)

 

这意味内存实际上并不是完全以byte形式组织的,而是以偏移量(offset)来给出具体地址的。

这样当我们采用对齐的地址访问时,比如从0x00开始访问四字节,显然四个字节储存于4个芯片,而且他们都有同样的偏移量(offset),这时我们就能一次获得所需的数据。

但是当从0x01开始读取4字节呢?此时前三个字节也是按顺序分别储存在1-3芯片中的,而且偏移量都是0,但是第四个字节却储存在偏移量为1的芯片0中。

在访问内存时,CPU需要给出偏移量offset,而发送偏移量的总线宽度大约是40位(64bit环境下),通常这样的总线只有一个。这意味着在一次内存访问周期内我们只能读取一个结果。

当然,要想一次读取两个offset的内容也不是不能实现,你可以增加用于发送地址的bus数量。对于一个64位的cpu,如果你希望在一个访问周期内读取未对齐的内存,你需要增加到8根总线。这意味着需要增加接近300个io。而通常cpu的管脚数量在700-2000之间,在这基础之上增加300将会是一个很大的改动。换句话说,就是会大大增加硬件的复杂程度。

同时,内存访问信号的频率是非常高的,增加的总线也会造成额外的噪声干扰。

当然,还有一种方法。由于非对齐访问最多也就访问两个不同的offset,而且这两个offset总是连续,我们可以再给内存内部加一根额外的线,这样就可以同时返回offset和offset+1两个偏移量上的数据了。

但是,这样意味着芯片内多了一些额外的加法器(用于给offset加一,得到下一个偏移量),所有的读操作都会在读取前增加一个计算操作。这一步会降低内存的时钟。于是乎,我们可能为了千分之一概率出现的非对齐访问,增加了99.9%的对齐访问的访问延时。显然这并不是一个明智的选择。

因此,CPU不支持,或者通过两次读取来实现非对齐访问也就有理有据了。

此外,访问非对齐的数据还存在一个问题:cache

通常来说,cache是和offset相关联的,不同的offset被不同的cache line缓存,因此,访问非对齐的数据也意味着多次的cache读取,同样会降低效率。

综上所述,这些也基本上是为何CPU要求内存访问对齐的原因了。//转载完

 

Cortex-M4处理器的内部资源

 

                                Cortex-M4存储模型(Memory Model)与MPU(Memory Protection Unit)

STM32F4系列提供的CPU外部资源

                Cortex-M4存储模型(Memory Model)与MPU(Memory Protection Unit)

 

总线矩阵:

总线矩阵是STM32单片机内最重要的硬件结构之一,通过总线矩阵灵活地将Cortex-M4处理器的内核总线(I-Code、D-Code、System BUS)与众多系统级外设(保证CPU正常运行)(如:片内SRAM、片内FLASH、数据DMA总线)或速度要求极高的应用级外设(为用户的具体应用提供服务)(如:以太网DMA总线、USB DMA总线等)相连接。

除此之外,总线矩阵还进一步提供了面向更外一层设备的总线接口APB、AHB和FSMC,其与众多应用级外设相连,并为Cortex-M4处理器提供了访问MCU片内设备(如:DMA外设总线、TIM、ADC、DAC、USART、SPI、USB等)和MCU片外高速设备(如:片外RAM、FLASH)的途径。

时钟系统(时钟树):

是整个单片机系统的心脏,为所有设备(CPU、存储器、总线、外设)提供时钟脉冲。

                       Cortex-M4存储模型(Memory Model)与MPU(Memory Protection Unit)

 

嵌入SRAM:

F429系列提供了大小256KB的系统SRAM,以及4KB的备份SRAM。

以CPU速度运行,可按字节、半字(16 位)或全字(32 位)访问,相当于是ST公司为Cortex-M4内核配备的外部Cache,可通过I-Code和D-Code总线分别访问!

还部分区域支持AHB总线上不同设备的并发访问。

嵌入Flash:

F429系列提供了1MB大小的片内FLASH,用于存储用户程序代码(Code区)。

相关文章:

  • 2022-02-23
  • 2022-12-23
  • 2021-05-10
  • 2021-06-27
  • 2022-01-24
  • 2021-06-13
  • 2021-10-10
  • 2022-12-23
猜你喜欢
  • 2021-12-26
  • 2022-12-23
  • 2021-10-30
  • 2022-01-20
  • 2021-06-28
  • 2021-07-30
  • 2021-04-11
相关资源
相似解决方案