如何防止ARM编译器5 armcc内联汇编程序中的LDM/STM指令扩展?

如何防止ARM编译器5 armcc内联汇编程序中的LDM/STM指令扩展?,c,assembly,arm,embedded,armcc,C,Assembly,Arm,Embedded,Armcc,我正在尝试使用ARM编译器5 armcc编译的.c文件中的内联汇编中的STM/LDM指令生成AXI总线突发访问 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指令序列。但是,编译器可能会在优化过程中将单

我正在尝试使用ARM编译器5 armcc编译的.c文件中的内联汇编中的STM/LDM指令生成AXI总线突发访问

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,这些指令的顺序是任意的。 这会影响性能,因为我们使用的硬件针对突发处理进行了优化。这也破坏了函数的正确性,因为我们使用的硬件考虑了单词的顺序并忽略了偏移量(但编译器认为更改指令顺序是安全的)

要解决这个问题,可以使用嵌入式汇编程序而不是内联汇编程序,但这会导致额外的函数调用,返回影响性能的结果

所以我想知道是否有一种方法可以在不损失性能的情况下正确生成LDM/STM?我们能够在GCC中实现这一点,但没有为armcc找到任何解决方案

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

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

所以我想知道是否有一种方法可以在不损失性能的情况下正确生成LDM/STM?我们能够在GCC中实现这一点,但没有为armcc找到任何解决方案

一点关于编译器优化的知识。这是最艰难的工作之一。任何编译器代码生成的核心可能都是在分配物理CPU寄存器时。大多数编译器都使用将“C”变量重命名为一组伪变量(或时间顺序变量)

为了使STMIA和LDMIA正常工作,您需要使加载和存储保持一致。即,如果它是
stmia[rx]、{r3,r7}
和类似
ldmia[rx]、{r4,r8}
的还原,则“r3”映射到新的“r4”,而存储的“r7”映射到还原的“r8”。这对于任何编译器来说都不容易实现,因为“C”变量将根据需要分配。同一变量的不同版本可能位于不同的寄存器中。要使
stm/ldm
工作,必须分配这些变量,以便寄存器以正确的顺序递增。也就是说,对于上面的
ldmia
,如果编译器想要将
r7
存储在
r0
中(可能是返回值?),那么它无法创建一条好的
ldm
指令而不生成额外的代码

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

有关GCC stm/ldm的问题,请参阅

以你为例,

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1)
{
    __asm {
        STMIA addr!, { w0, w1 }
    }
}
inline
的价值在于可以将整个函数体放在代码中。调用者可能在寄存器R8和R4中有
w0
w1
。如果函数不是内联的,则编译必须将它们放在R1和R2中,但可能会产生额外的移动。任何编译器都很难一般地满足
ldm/stm
的要求

这会影响性能,因为我们使用的硬件针对突发处理进行了优化。这也破坏了函数的正确性,因为我们使用的硬件考虑了单词的顺序并忽略了偏移量(但编译器认为更改指令顺序是安全的)

如果硬件是总线上的特定非内存从机外围设备,则可以将写入此从机的功能包装在外部包装中,并强制寄存器分配(请参阅),以便
ldm/stm
工作。这将导致性能下降,这可以通过设备驱动程序中的一些自定义汇编程序来缓解

但是,听起来设备可能是内存?在这种情况下,您有一个问题。通常,像这样的内存设备将只使用缓存?如果您的CPU有一个MPU(内存保护单元),并且可以同时启用数据和代码缓存,那么您可以解决这个问题。缓存线将始终是突发访问。只需在代码中小心设置MPU和数据缓存。OPs Cortex-M0+没有高速缓存,且设备为非内存设备,因此不可能(也不需要)


如果您的设备是内存,而您没有数据缓存,那么您的问题可能无法解决(无需大量工作),您需要不同的硬件。或者你可以把它像外围设备一样包装起来,然后在性能上大受打击;失去随机访问内存设备的好处。

如果您非常关心性能,请在单独的汇编文件中写入更多您需要的内容。考虑到编译器对其余代码的处理有多糟糕,内联C函数中的一条指令不会给您带来多少好处。我的操作原则是——如果你关心时间关键型例程的性能,那就自己编写(用汇编语言编写)。@imiron13:我怀疑你完蛋了。Kiel inline assembly让优化器脱颖而出,缺乏对其“优化”内容的细粒度控制。如果您使用普通的易失性指针来确保64位类型的写入程序顺序,以尝试组合写入操作,那么代码生成会有多糟糕?@BitBank:我的假设是,性能影响并不是孤立于单个关键的内部循环,而c