[收到很多短信,因为我想尽我所能详细说明我的问题。]
我正在为 Cortex-M0 优化手写的 ARM 汇编代码。我使用的开发板是 STMicro STM32F0Discovery,它有一个 STM32F051R8 控制器。控制器以 48 MHz 运行。
不幸的是,在进行优化时,我得到了一些非常奇怪的循环计数。
例如,nop
在我的代码中添加一个循环应该总共添加 2 个循环(循环 2 次)。但是,这样做会增加大约 1800 个额外的周期。现在,当我添加一个额外的nop
(总共 2nop
秒)时,循环计数确实增加了预期的 4 个循环。
对于下面的示例代码,我得到了类似的奇怪结果。示例代码显示,顶部摘录:c = 25 * a + 5 * b
. 底部摘录是c = 5 * (5 * a + b)
。因此,底部的应该更快,因为它需要 1 less mov
。但是,改变这一点:
movs r4, #25
muls r3, r4, r3
add r2, r3
ldrb r3, [r6, #RoundStep]
movs r4, #5
muls r3, r4, r3
add r2, r3
进入这个:
movs r4, #5
muls r3, r4, r3
ldrb r5, [r6, #RoundStep]
add r3, r5
muls r3, r4, r3
add r2, r3
不会将速度提高预期的 1 个周期,而是将速度降低或多或少 1000 个周期...
为了计算周期,我使用 SysTick 计数器,从最大值开始向下计数,并在溢出中断时增加溢出计数器。我为此使用的代码或多或少与ARM 网站的这段摘录相同,但针对我正在使用的 Cortex-M0 进行了重写。我的代码足够快,以至于在测量期间不会发生溢出中断。
现在,我开始认为计数器给了我错误的值,所以我还为我躺在身边的 TI Stellaris LaunchPad 编写了一些代码。这是一个以 80 MHz 运行的 Cortex-M4F。该代码测量某个引脚保持高电平的周期数。当然,M0 的时钟和 M4F 的时钟不同步运行,因此报告的周期计数略有不同,我通过对测量的周期计数 ( avg = 0.995 * avg + 0.005 * curCycles
) 和重复测量 10000 次。
M4F 测量的时间与 M0 测量的时间相同,因此“不幸的是”SysTick 计数器在 M0 中工作得很好。
起初我以为这些额外的延迟是由流水线停顿引起的,但一方面 M0 似乎太简单了,另一方面我找不到 M0 流水线的任何详细信息,所以我无法验证.
所以,我的问题是:这里发生了什么?为什么添加一个nop
会使我的函数需要额外的 1000 个循环/循环,但两个nop
s 只会将循环计数增加 2?为什么删除指令会使我的代码执行速度变慢?