为什么要字节对齐?

2,905 阅读4分钟

说起字节对齐,我们先来看看存储器对地址的安排。

多模块交叉存储器

一个由若干个模块组成的主存储器时线性编址的。这些地址在各模块中如何安排,有两种方式:一事时顺序方式,一种是交叉方式

在常规主存储器设计中,访问地址采用顺序方式。如图,存储器容量为32字,分成M0-M3四个模块,每个模块存储8个字。访问地址按顺序分配给一个模块后,接着又按顺序分给下一个模块。这样,存储器的32个字可由5位地址寄存器指示,其中高2位为选择4个模块中的一个,低三位选择每个模块中的8个字。

这种方式优点是,一个模块故障,其他模块仍然可以照常工作,并且通过增加模块来扩展存储器容量也很方便。缺点是各模块一个接一个的串行工作,因此存储器的带宽受到了限制。

另一种方式是交叉方式。如图,存储器容量也是32个字,也分成四个模块,每个模块8个字。但地址的分配方法是交叉的。先将4个线性地址0,1,2,3分配给M0,M1,M2,M3,再将线性地址5,6,7,8分配给M0,M1,M2,M3,一直重复,直到所有线性地址分配完。当存储器寻址时,用地址寄存器低2位来选择4个模块中的一个,而高3位用来选择模块中的8个字。

使用低位字段经过译码选择不同的模块,用高位字段指向相应模块内的存储字,这样,连续的线性地址分布在相邻模块,而同一个模块内的地址都是不连续的。对连续字的成块传送,交叉方式的存储器可以实现多模块流水式并行存取,大大提高存储器的带宽。

字节对齐

我们的计算机通常采用的是第二种方式。

对于奔腾32位CPU连接存储如下图所示:

其中D0~D31是连接到32位数据总线上的。32位地址总线共能寻址4GB的空间。4GB内存空间由4块内存芯片组成,每块1GB,CPU的A31~A2地址总线接在每一块内存芯片上(图中未画出),其实CPU给出的主存地址没有A1~A0,替代的是4个字节允许信号BE3~BE0,BE3~BE0控制是否允许被选中的存储单元完成读/写访问。图的左边是16进制表示的内存地址,这个地址是对外的,对于每个内存芯片自己看来地址排布还是0,1,2,3...这样排布的。

通过上面的接法,CPU可以实现按双字(32),字(16),字节(8)访问存储器。

按双字访问

通过CPU的主存地址中的A31~A2选中4块存储芯片中的同一个地址(对于存储芯片自己来说,对外不是一个同一个地址),然后使BE3~BE0全有效时即可以读出连续的双字(32位)。

按字访问

和访问双字类似,通过控制BE3~BE0同时选中连续的两块相邻地址的芯片即可。

按字节访问

和访问双字类似,通过控制BE2~BE0选中其中一个存储芯片即可。


数据的存储地址是数据字节长度的整数倍,则称为字节对齐。

知道了CPU是如何读取存储字后我们发现,对于非字节对齐的字或者双字,需要两个周期才能够获取。


总结

由于CPU与存储器的连接方式。并且CPU的主存地址并没有A1~A0,导致CPU发出的内存的地址永远都是4的倍数(32位CPU)。如果数据的存放地址不做字节对齐,对正常的工作不会产生任何影响,但是性能会降低,CPU需要2个周期来读取后将数据拼接起来才能读取到数据。如果数据的存放地址都是字节对齐的,那么CPU就可以在一个周期内读出一个双字。


参考资料

CPU访问内存