【发布时间】:2016-01-15 23:16:13
【问题描述】:
我正在尝试使用 STM/LDM 指令在使用 ARM Compiler 5 armcc 编译的 .c 文件中的内联汇编中生成 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 个字节,完整请求的第一个字是写入的第一个字(即使偏移量非零)。
【问题讨论】:
-
如果您非常关心性能,那么在单独的汇编文件中编写更多您需要的内容。考虑到编译器对其余代码的处理有多糟糕,内联 C 函数中的单个指令不会让您得到太多。我的操作原则始终是 - 如果您关心时间关键例程的性能,请自己编写(在汇编程序中)。
-
@imiron13:我怀疑你被搞砸了。 Kiel 内联汇编让优化器开箱即用,并且对其“优化”的内容缺乏细粒度的控制。如果您使用普通的 volatile 指针来确保写入器顺序与 64 位类型一起尝试组合写入,那么代码生成有多糟糕?
-
@BitBank:我的假设是,性能损失并不局限于单个关键的内循环,可以很容易地手动调整,但是写入是内联生成到代码库的重要部分中的。
-
@BitBank:情况就像描述的doynax一样,大部分硬件都针对突发事件进行了优化,在汇编中实现整个HAL层是不合理的。
-
@doynax:我还没有尝试去引用 (volatile uint64_t*),也许它会产生 LDM/STM,但在其他情况下也需要 16-64 字节突发,所以它似乎不是可以用 C 代码来表达。
标签: c assembly arm embedded armcc