使用寄存器和内联汇编(ARM)

时间:2013-11-01 01:29:58

标签: c arm inline-assembly

我有一个小程序,我试图用它来以编程方式识别CPU频率。

我的程序结构如下:

  • 设置闹钟
  • while(1)循环中的递增寄存器
  • SIGALRM
  • 时计算速度

最初,我正在使用

register unsigned int cycles asm("r6");  
...  
while(1)
    cycles++;

使用objdump后,我注意到这实际上转化为以下内容:

9aa0:       e1a03006        mov     r3, r6  
9aa4:       e2833001        add     r3, r3, #1  
9aa8:       e1a06003        mov     r6, r3  
9aac:       eafffffb        b       9aa0 <estimate_from_cycles+0x1cc>  

由于我不确定为什么这转换为3条指令,我尝试使用内联汇编:

register unsigned int cycles asm("r6");  
...  
while(1)
    asm("add r6, r6, #1);

这转化为:

9aa0:       e2866001        add     r6, r6, #1  
9aa4:       eafffffd        b       9aa0 <estimate_from_cycles+0x1cc>  
  • 为什么之前的实现转换为3条指令?
  • 在ARM平台上,b <label>指令需要3个周期。但是,减去ARM上的操作,只使用1个周期。
    • 有什么方法可以减去PC寄存器吗?
    • 甚至允许在PC上减去?
    • 还有其他方法可以减少实现相同逻辑所需的周期数吗?

编辑:我正在使用CodeSourcery的arm-none-linux-gnueabi-工具链而没有优化

1 个答案:

答案 0 :(得分:0)

由于您未启用任何优化,因此很可能将实现转换为3条指令。

但是,从快速测试来看,无论如何你看起来都必须编写内联汇编,因为当我使用-O3 -fomit-frame-pointer编译以下内容时

void test(void) {
        register unsigned int cycles asm("r6");
        while(1) cycles++;
}

该例程简单地优化到

00000000 <test>:
   0:   eafffffe    b   0 <test>

即使添加volatile也没用,因为编译器确实知道写入CPU寄存器肯定不会产生任何副作用(与内存不同),因此对它进行优化是合理的。

回答你的其他问题,

  • 有什么方法可以减去PC寄存器吗?
  • 甚至允许在PC上减去?

是的,当然。但我不确定这是否还需要一个周期。

  • 还有其他方法可以减少实现相同逻辑所需的周期数吗?

作为旁注,您的逻辑不会给出非常准确的结果,因为您的过程可能会在您开始和完成测量之间切换。

你期待:

<                    your process                     >
|<---------------your alarm duration----------------->|

何时,它可能更像(其中|是上下文切换):

<your process> | <other processes ...> | <your process>
|<---------------your alarm duration----------------->|