我想将ARM Cortex M0+延迟n个周期,而不使用计时器,代码大小尽可能小。(我认为这要求使用集会。)
0循环的延迟很简单,没有代码。一个周期的延迟是一个NOP。两个周期的延迟是两个NOPs。
在什么时候开始循环(代码大小)是有效的?
最紧的循环需要多少周期?设置时间是几点?
贴上答题:
以下C代码:
register unsigned char counter = 100;
while (counter-- > 0) {
asm("");
}
当使用gcc和-O3编译时:
mov r3, #100
.L5:
sub r3, r3, #1
uxtb r3, r3
cmp r3, #0
bne .L5
这要么说明手工编码ARM程序集仍然有目的,要么(更有可能)说明上面的C代码不是向编译器传达我想要做的事情的最佳方式。
评论?
发布于 2014-12-16 20:57:11
代码将取决于具体的n是什么,以及它是否需要动态变量,但是给定M0+核心的指令时序,为特定例程建立边界是非常简单的。
对于最小的(6字节)完全循环,有一个固定的8位直接计数器:
movs r0, #NUM ;1 cycle
1: subs r0, r0, #1 ;1 cycle
bne 1b ;2 if taken, 1 otherwise
有了NUM=1
,我们可以得到至少3个循环,再加上在765个循环(当然,您可以从NUM=0
获得2^32次迭代,但这似乎有点傻)的每个额外循环到NUM=255
的3个循环。这使得循环的下界在大约6个周期内是实用的。有了一个固定的循环,就很容易将NOPs (甚至嵌套循环)放入其中,以延长每次迭代,并在前后对齐循环长度的非倍数。如果您可以在需要开始等待之前在寄存器中安排许多迭代,那么您可能会丢失初始的mov
,并且几乎有3个或多个循环的倍数,减去一个。如果您需要对可变延迟进行单周期解析,则初始设置成本将更高一些,以便对其余部分进行校正(我会这样做:将计算出的分支放入NOP雪橇中)。
我假设,如果您正处于周期关键时间点,您已经中断了(否则会在CPSID
的某个地方添加另一个循环),并且您没有任何总线等待状态,将额外的周期添加到指令获取中。
至于在C中尝试这样做:您必须黑进一个空的asm
,以防止“无用”循环被优化掉,这是一种提示。抽象的C机器没有“指令”或“循环”的概念,所以根本就没有办法用语言可靠地表达这一点。试图依赖特定的C结构来编译到合适的指令是极其脆弱的--更改编译器标志;升级编译器;更改影响寄存器分配的远程代码,从而影响指令的选择;等等--几乎任何事情都可能意外地更改生成的代码,所以我认为手工编码的程序集是循环精确代码的唯一合理方法。
发布于 2014-12-16 20:55:38
我能想到的最短的手臂循环是这样的:
mov r0, #COUNT
L:
subs r0, r0, #1
bnz L
因为我没有这个设备,所以不知道时间。这些都是核心依赖。
https://stackoverflow.com/questions/27510198
复制相似问题