2015-10-17 68 views
2

我试图产生 AXI总线突发访问与ARM编译器armcc 5编译.c文件使用内联组件STM/LDM指令。如何防止ARM Compiler 5 armcc内嵌汇编程序中的LDM/STM指令扩展?

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1) 
{ 
    __asm { 
     STMIA addr!, { w0, w1 } 
    } 
} 

但ARM编译器armcc用户指南,第7.18段是说: “所有的LDM和STM指令被扩展为等效的LDR和STR指令序列然而,编译器可能因此重组的单独的指令在优化过程中转换为LDM或STM。“

这就是真正发生的事情在实践中,LDM/STM被扩展成一组的LDR/STR在某些情况下,这些instuctions的顺序是任意的。 这会影响性能,因为我们使用HW优化了突发处理。此外,这破坏了函数的正确性,因为我们使用的HW考虑了字的序列并忽略了偏移量(但编译器认为改变指令的顺序是安全的)。

要解决这一点,是可以使用的,而不是内联汇编嵌入式汇编程序,但是这会导致额外的函数调用,返回什么影响性能。

所以我想知道如果有一种方法来生成LDM/STM正确不失的表现?我们能够在GCC中做到这一点,但没有找到任何解决方案。

目标CPU:Cortex M0 +(ARMv6-M)。

编辑: 从属设备都是片上设备,其中大多数是非存储设备。对于支持地址空间突发访问区域的每个非存储器从站寄存器(例如[0x10000..0x10100]),我不完全确定为什么,也许CPU或总线不支持固定(非增量)地址。 HW忽略该区域内的偏移量。例如,完整请求可以是16个字节,并且完整请求的第一个字是第一个写入的字(即使偏移量不为零)。

+1

如果你很在乎性能,然后写更多的,你在一个单独的汇编程序文件所需要的。考虑到编译器处理代码的其余部分有多糟糕,内联C函数中的单个指令不会让你感到太多。我的运营主体总是 - 如果您关心时间关键的例程的性能,请自己写(使用汇编程序)。 – BitBank

+0

@ imiron13:我怀疑你是搞砸了。基尔内联汇编让优化器无所不能,对“优化”功能缺乏细粒度的控制。如果您使用正常的易失性指针来确保写入器与64位类型的顺序以尝试组合写入,那么代码生成有多糟糕? – doynax

+0

@BitBank:我的假设是,性能命中并不是孤立于单个重要的内部环路,这可以很容易地手动调整,但写入内联生成代码库的重要部分。 – doynax

回答

1

所以我想知道是否有一种方法可以正常生成LDM/STM而不会丢失性能?我们能够在GCC中做到这一点,但没有找到任何解决方案。

约编译器优化一点点。 Register allocation是最难的工作之一。任何编译器代码生成的核心可能都在于它分配物理CPU寄存器的时间。大多数编译器使用Single static assignment or SSA将'C'变量重命名为一堆伪变量(或时序变量)。

为了让您的STMIA和LDMIA工作,你需要在加载和存储是一致的。也就是说,如果它是stmia [rx], {r3,r7}并且像ldmia [rx], {r4,r8}这样的恢复具有'r3'映射到新的'r4'并且存储的'r7'映射到恢复的'r8'。对于任何编译器来说,这并不简单,因为'C'变量将根据需要进行分配。相同变量的不同版本可能在不同的寄存器中。要使stm/ldm工作,必须分配这些变量,以便按正确的顺序进行寄存器增量。也就是说,如果编译器希望存储的r7位于r0(可能是返回值?),上面的ldmia,则无法创建好的ldm指令而不生成其他代码。

你可能已经得到了gcc来生成这个,但它可能是运气。如果你只使用gcc,你可能会发现它不能正常工作。

参见:ldm/stm and gcc与GCC STM/LDM问题。

以你的榜样,

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1) 
{ 
    __asm { 
     STMIA addr!, { w0, w1 } 
    } 
} 

inline值是整个函数体可以放在右边的代码。调用者可能在寄存器R8和R4中有w0w1。如果函数不是inline,那么编译时必须将它们放在R1和R2中,但可能会产生额外的移动。任何编译器一般难以满足ldm/stm的要求。

这会影响,因为HW我们使用的突发处理优化的性能。此外,这破坏了函数的正确性,因为我们使用的HW考虑了字的序列并忽略了偏移量(但编译器认为改变指令的顺序是安全的)。

如果硬件在总线上一个特定的非存储器从属外围,则可以包裹的功能写入到该从机在外部包裹件和强制寄存器分配(见AAPCS),使得ldm/stm将工作。这会导致性能下降,这可以通过设备驱动程序中的某个自定义汇编程序来缓解。

然而,这听起来像设备可能是内存吗?在这种情况下,你有一个问题。通常情况下,像这样的内存设备只会使用缓存?如果您的CPU有一个MPU(内存保护单元)并且可以启用数据和代码缓存,则可以解决此问题。缓存行将始终是突发访问。只需在代码中设置MPU和数据高速缓存即可。 的OP的Cortex-M0 +不具有高速缓存和装置是非存储器所以这将是不可能的(也不需要)。

如果你的设备是内存,你有没有数据缓存那么您的问题可能是无法解决的(没有付出巨大的努力),你需要不同的硬件。或者你可以像外围设备一样包装它,并采取性能打击;失去了存储设备随机存取的好处。

+0

(这与您在帖子中链接的问题更相关,但我无法在此发表评论)。 'gcc问题'意味着可以可靠地生成突发,但是由于显式的寄存器分配,它可能不是最优的? – imiron13

+0

虽然,您的里程可能会有所不同,具体取决于GCC版本和选项标志。我发现唯一可靠的方法是使用函数调用并依赖寄存器参数或者指定gcc寄存器'asm'变量。如果你不这样做,你可能会得到神秘的关于寄存器的stm/ldm乱序的消息。也就是说,有人更改代码或编译器选项以及GCC选项寄存器不起作用。 –

+0

如果这一切都是'芯片上的'并且你的公司没有设计它,但是一些大公司和芯片组被广泛使用,我怀疑有某种总线配置需要。很难相信商业SOC会在编辑中遇到问题。任何使用该芯片的人都会遇到同样的问题。如果芯片是未来产品的样本,那么这可能是一个勘误,我期望在芯片进入大规模生产之前能够修复。 –