我目前正在开发一个简单的ARM固件。其中,我参与了与中断有关的部分。我将异常向量表中的IRQ异常向量与中断控制器中的中断处理程序进行了如下连接:
__attribute__ ((interrupt ("IRQ"))) void Irq_Handler(void)
{
interrupt_handler();
}
并转换为ARM汇编代码:
sub lr, lr, #4
push {r0, r1, r2, r3, r4, fp, ip, lr}
add fp, sp, #28
bl 0 <interrupt_hanlder>
sub sp, fp, #28
ldm sp!, {r0, r1, r2, r3, r4, fp, ip, pc}^
我对此汇编代码有几个问题:
谢谢!
为什么将寄存器“ r0,r1,r2,r3,r4,fp,ip,lr”压入堆栈?
之所以这样做,是因为这些寄存器可以通过功能interrupt_handler()
进行修改。中断会在任何地方中断正在运行的程序。例如这里:
ldm r0, {r2, r3}
<=== The interrupt interrupts the program here
add r1, r2, r3
如果中断修改了某些寄存器(在示例中为r2
或r3
,则被中断的程序将无法再正确运行。
因此,中断必须将所有寄存器恢复为其原始值。
函数interrupt_handler()
不会修改寄存器r5
,r6
,...,因此中断处理程序不需要恢复这些寄存器。
它将8个寄存器压入堆栈。但是为什么它不减去32(4 * 8)而是28(4 * 7)?
出于某种原因,fp
寄存器应包含值sp+28
。也许它应该指向lr
寄存器的存储值。
假设sub sp, fp, #28
的值自指令sp
以来没有变化,则fp
的指令将恢复add fp, sp, #28
的值。
在您的情况下,sp
没有更改,因此该指令是多余的。
我不知道第6行末
^
的含义。
^
用于ldm
和stm
指令,并且具有两种不同的效果。
两个效果之一是,加载pc
寄存器也将加载psr
寄存器。
要从中断返回,必须恢复psr
寄存器。
[请注意,在早期的ARM CPU中,寄存器r15
既包含pc
寄存器(仅24位宽),又包含psr
寄存器(其8位宽)。没有ldm
的^
将使寄存器psr
的8 r15
位保持不变,而使用^
将从内存中加载所有32位。
在当前的ARM CPU中不再如此。但是,使用^
加载psr
时,使用pc
仍会恢复ldm
寄存器的值。