对齐和未对齐的内存访问有什么区别?

我在 TMS320C64x DSP 上工作,我想使用内部函数(汇编指令的 C 函数),它有

ushort & _amem2(void *ptr);
ushort & _mem2(void *ptr);

在哪里 _amem2 执行 2 个字节的对齐访问,并且 _mem2 进行未对齐的访问。

我什么时候应该使用哪个?

有帮助吗?

解决方案

这是对准的存储器访问意味着指示器(作为一个整数)被称为对准的特定于类型的值的倍数。该对准是天然的地址的多个其中类型必须是,或应当被存储(例如,对于性能方面的原因)在CPU上。例如,CPU可能需要将所有两个字节加载或存储是通过为二的倍数的地址进行。对于小的原语类型(下4个字节),对准几乎总是类型的大小。对于结构,对准通常是任何成员的最大对齐。

C编译器总是把你在声明满足了“正确的”对齐地址变量。所以,如果ptr指向例如一个uint16_t变量,它会对齐,你可以使用_amem2。您需要使用_mem2仅当您正在访问例如经由I / O,或字节的字符串的中间接收的填充字节数组。

其他提示

许多计算机架构存储存储器中的每几个字节的“字”。例如,英特尔32位架构的存储32位,每个4个字节字。存储器然而在单字节电平,被寻址;因此一个地址可被“对准”,这意味着它开始于一个字边界,或“非对齐”,意思是它不

在某些体系结构的某些存储器操作可能较慢或甚至完全不允许对未对齐地址。

所以,如果你知道你的地址是在右边的地址一致,则可以使用_amem2(),速度。否则,你应该使用_mem2()。

对齐地址是所讨论的访问大小的倍数的地址。

  • 对 4 的倍数地址上的 4 字节字的访问将被对齐
  • 从地址(例如)3 访问 4 个字节将是未对齐访问

很有可能的是 _mem2 也适用于未对齐访问的函数将不太适合在其代码中获得正确的对齐。这意味着 _mem2 功能可能比它的成本更高 _amem2 版本。

因此,当您需要性能时(特别是当您知道访问延迟很高时),请谨慎确定何时可以使用对齐访问。这 _amem2 正是为了这个目的而存在——当您知道访问一致时为您提供性能。

当涉及 2 字节访问时,识别对齐操作非常简单。
如果该操作的所有访问地址都是“偶数”(即它们的 LSB 为零),则具有 2 字节对齐。这可以很容易地检查,

if (address & 1) // is true
    /* we have an odd address; not aligned */
else
    /* we have an even address; its aligned to 2-bytes */

我知道这是一个选择的答案一个老问题,但没有看到任何人解释的答案是什么对齐和未对齐的内存访问的区别...

无论是DRAM或SRAM或闪存或其他。采取作为一个简单的示例中,建立了比特的特定SRAM将建出固定数量的比特宽的和行深的固定数目的的SRAM。让说32个位宽和几个/多行深。

如果我做一个32位写在该SRAM到地址0x0000,解决此SRAM存储器控制器可以简单地做一个单一的写周期到行0。

如果我做一个32位写在该SRAM,以解决0×0001,假定是允许的,则控制器将需要做0行的读操作,修改三个字节,保存一个,和写入到行0,然后读第1行修改一个字节留给其他三个为发现和写回。哪些字节得到改性或不具有与端序用于制做。

前者是对准并且后者未对齐的,明确的性能差异加上需要额外的逻辑,以便能够执行四个存储器周期和合并字节通道。

如果我是读取来自地址0×0000 0然后行的单一读出,完成32位。但是,从0×0001阅读,我必须做两次读取ROW0和ROW1并根据系统的设计只是那些64位送回处理器可能是两个总线时钟,而不是一个。或存储器控制器具有额外的逻辑,使得32位被在一个总线周期在数据总线上对齐。

16位的读操作是好一点,读出从0x0000,0x0001的和0×0002将仅在读取从ROW0并且可以基于系统/处理器设计发送这些32位背部和所述处理器提取它们或在移位他们存储器控制器,使得它们落在特定字节通道所以不必须处理器周围旋转。一方或另一方有权如果不能兼顾。从为0x0003读虽然是像上面你必须读行0和ROW1作为字节中的一个是在每一个,然后或者发送64位背部的处理器以提取或存储器控制器的位组合成一个32位总线响应(假设处理器和存储器控制器之间的总线为32个位宽。这些实施例)。

一个16位的写入虽然总是具有至少一个在本例中的SRAM读 - 修改 - 写操作,地址为0x0000,0x0001的和0×0002读ROW0修改两个字节和写回结束。地址为0x0003读两行每修改一个字节和写回。

8位只需读取包含该字节的一行,写虽然是一个行的读 - 修改 - 写。

在ARMV4不喜欢不对齐的,虽然你可以禁用的陷阱,结果并不像你所期望的上面,并不重要,当前武器允许未对齐的,给你的上述行为可以更改控制寄存器中的位,然后将其将中止对齐传输。 MIPS用来不允许,不知道他们现在怎么做。 86,68K等,允许和存储器控制器可不得不这样做最多的工作。

这是不容许它的设计显然是在什么有些人会说是程序员别人的负担可能会说这是对程序员程序员或更容易没有额外的工作性能和较少的逻辑。对齐或不你也可以看到,为什么它可以最好不要尝试通过使8个变量保存任何的内存,但继续烧32位字或任何一个寄存器的自然大小或总线。它可以帮助你的表现在一些字节的小的成本。更不用说额外的代码编译器将需要添加,使让说,32位寄存器模仿一个8位的变量,遮蔽,有时符号扩展。当使用寄存器本地大小的附加说明是不需要的。您也能够将多个东西放进总线/内存宽的位置,做一个存储周期收集或编写然后将它们使用一些额外的指令到m寄存器之间anipulate不花费上的指令的数量的RAM和一个可能的洗涤。

我不同意,编译器会始终对准目标的数据正确,有办法打破。如果犯规支持未对齐,你会打故障的目标。程序员永远不会需要谈论这一点,如果总是做的对基于任何合法的代码,你能想出的编译器,会有除非它是对性能没有理由为这个问题。如果你不控制无效PTR地址对齐或没有,那么你必须使用MEM2()对齐访问所有的时间,或者你有根据的PTR作为NIK的价值做一个if-then-else的在你的代码指出。通过声明为无效的C编译器现在已经没有办法与你的定位正确处理,它不会得到保证。如果你把一个char * PRT并且将其提供给这些函数的所有的赌注都关闭编译器得到它的权利,没有你增加额外的代码,通过埋在MEM2()函数或这两个函数之外。所以写在你的问题MEM2()是唯一正确的答案。

DRAM说在桌面/膝上型计算机使用趋向于64或72(用ECC)位宽,并把它们每一个的访问被对准。即使记忆棒实际上是由8位宽或16个或32位宽的芯片。 (这可以与因各种原因电话/片剂改变)存储器控制器和理想的是至少一个高速缓存坐在该DRAM的前面,使得那些比总线宽度小的未对准或甚至对齐访问读 - 修改 - 写操作处理与高速缓存SRAM的方式更快,和DRAM存取全部对齐全总线宽度存取。如果在DRAM的前面没有高速缓存并且所述控制器被设计用于全宽访问,然后将其表现最差,如果设计用于单独点亮所述字节通道(假定8比特宽的芯片),那么你没有读 - 修改-writes但更复杂的控制器。如果典型的使用情况是一个高速缓存(如果有一个设计),那么它可能没有意义有在控制器的每个字节通道额外的工作,但有它只是知道该怎么做全总线宽度尺寸转移的或倍数。

_mem2是更普遍的。如果PTR对齐或不它会工作。 _amem2是更严格的:它要求PTR对齐(虽然可以认为是稍微更有效)。因此,使用_mem2,除非你能保证PTR总是一致。

许多处理器具有存储器访问对齐限制。对齐访问要么产生一个异常中断(例如ARM),或仅仅是较慢的(例如86)。

_mem2可能是作为取两个字节,并使用移和或按位操作,使16位USHORT了出来实现。

_amem2可能只是读出从指定PTR 16位USHORT。

我不知道的TMS320C64x具体但我猜想它需要16位存储器访问16位对齐。所以,你可以使用_mem2始终但是性能损失,并且_amem2的时候可以保证PTR是偶地址。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top