为什么中断服务程序 PUSH {r3,r4,r5,lr} 但 POP {r0,r4,r5,lr} 导致 ERROR?
Why the interrupt service routine ,PUSH {r3,r4,r5,lr} but POP {r0,r4,r5,lr},which lead to ERROR?
我正在使用IAR编译例程,但是运行在ARM A7上出错;然后当我打开 IAR 生成的 .lst 文件时,我得到了下面的问题。
是一个ISR
,先是push {r3, r4, r5, lr}
,但是POP {r0, r4, r5, lr}
的时候return,R0
的值变成了R3
的值才push。因此,当从 irqHandler
编辑 return 时,R0
是错误的,这会导致后续例程出错。
为什么 ?
void irqHandler(void)
{
878: e92d4038 push {r3, r4, r5, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
87c: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
880: e302000c movw r0, #8204 ; 0x200c
884: e7900004 ldr r0, [r0, r4]
888: e1b00b00 lsls r0, r0, #22
88c: e1b00b20 lsrs r0, r0, #22
890: e1b05000 movs r5, r0
if(id_spin<32)
894: e3550020 cmp r5, #32
898: 2a000000 bcs 8a0 <irqHandler+0x28>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
89c: eafffffe b 89c <irqHandler+0x24>
}
else
{
(pFuncIrq[id_spin-32])();
8a0: e59f0010 ldr r0, [pc, #16] ; 8b8 <.text_8>
8a4: e1b01105 lsls r1, r5, #2
8a8: e0910000 adds r0, r1, r0
8ac: e5100080 ldr r0, [r0, #-128] ; 0x80
8b0: e12fff30 blx r0
}
}
8b4: e8bd8031 pop {r0, r4, r5, pc}
没关系,因为R0-R3、R12、LR、PC、xPSR在硬件调用中断向量例程时会自动入栈。当 bx
、ldm
、pop
或 ldr
和 PC
被调用时,硬件执行中断例程退出弹出这些寄存器。
不要检查你的编译器。它知道自己在做什么。检查错误逻辑 - 特别是在中断处理程序中打印字符串。
abi 需要一个 64 位对齐的堆栈,因此 r3 的压入简单地促进了这一点。可以选择任何尚未指定的寄存器。同样,在 pop 上,他们需要清理堆栈,该函数的原型为 void,因此无需关心 return (r0) 并且预计不会保留 r0-r3,因此没有理由在每个上匹配 r3两端也不匹配 r0。
如果他们在推送时选择了编号高于 r3(例如 r6)的寄存器,则需要在弹出时匹配该寄存器。否则 pop 必须是 r0-r3 之一才能不破坏非易失性寄存器。 (无法推送 r3 然后弹出 r6 会破坏 r6)
assemble 关键字 __irq __arm 代码如下:
__irq __arm void irqHandler(void)
{
878: e24ee004 sub lr, lr, #4
87c: e92d503f push {r0, r1, r2, r3, r4, r5, ip, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
880: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
884: e302000c movw r0, #8204 ; 0x200c
888: e7900004 ldr r0, [r0, r4]
88c: e1b00b00 lsls r0, r0, #22
890: e1b00b20 lsrs r0, r0, #22
894: e1b05000 movs r5, r0
if(id_spin<32)
898: e3550020 cmp r5, #32
89c: 2a000000 bcs 8a4 <irqHandler+0x2c>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
8a0: eafffffe b 8a0 <irqHandler+0x28>
}
else
{
(pFuncIrq[id_spin-32])();
8a4: e59f0010 ldr r0, [pc, #16] ; 8bc <.text_8>
8a8: e1b01105 lsls r1, r5, #2
8ac: e0910000 adds r0, r1, r0
8b0: e5100080 ldr r0, [r0, #-128] ; 0x80
8b4: e12fff30 blx r0
}
}
8b8: e8fd903f ldm sp!, {r0, r1, r2, r3, r4, r5, ip, pc}^
Cortex A7 PUSH log,它只是压入7个寄存器,所以32位对齐就可以了
关注 link 是日志信息:
我正在使用IAR编译例程,但是运行在ARM A7上出错;然后当我打开 IAR 生成的 .lst 文件时,我得到了下面的问题。
是一个ISR
,先是push {r3, r4, r5, lr}
,但是POP {r0, r4, r5, lr}
的时候return,R0
的值变成了R3
的值才push。因此,当从 irqHandler
编辑 return 时,R0
是错误的,这会导致后续例程出错。
为什么 ?
void irqHandler(void)
{
878: e92d4038 push {r3, r4, r5, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
87c: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
880: e302000c movw r0, #8204 ; 0x200c
884: e7900004 ldr r0, [r0, r4]
888: e1b00b00 lsls r0, r0, #22
88c: e1b00b20 lsrs r0, r0, #22
890: e1b05000 movs r5, r0
if(id_spin<32)
894: e3550020 cmp r5, #32
898: 2a000000 bcs 8a0 <irqHandler+0x28>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
89c: eafffffe b 89c <irqHandler+0x24>
}
else
{
(pFuncIrq[id_spin-32])();
8a0: e59f0010 ldr r0, [pc, #16] ; 8b8 <.text_8>
8a4: e1b01105 lsls r1, r5, #2
8a8: e0910000 adds r0, r1, r0
8ac: e5100080 ldr r0, [r0, #-128] ; 0x80
8b0: e12fff30 blx r0
}
}
8b4: e8bd8031 pop {r0, r4, r5, pc}
没关系,因为R0-R3、R12、LR、PC、xPSR在硬件调用中断向量例程时会自动入栈。当 bx
、ldm
、pop
或 ldr
和 PC
被调用时,硬件执行中断例程退出弹出这些寄存器。
不要检查你的编译器。它知道自己在做什么。检查错误逻辑 - 特别是在中断处理程序中打印字符串。
abi 需要一个 64 位对齐的堆栈,因此 r3 的压入简单地促进了这一点。可以选择任何尚未指定的寄存器。同样,在 pop 上,他们需要清理堆栈,该函数的原型为 void,因此无需关心 return (r0) 并且预计不会保留 r0-r3,因此没有理由在每个上匹配 r3两端也不匹配 r0。
如果他们在推送时选择了编号高于 r3(例如 r6)的寄存器,则需要在弹出时匹配该寄存器。否则 pop 必须是 r0-r3 之一才能不破坏非易失性寄存器。 (无法推送 r3 然后弹出 r6 会破坏 r6)
assemble 关键字 __irq __arm 代码如下:
__irq __arm void irqHandler(void)
{
878: e24ee004 sub lr, lr, #4
87c: e92d503f push {r0, r1, r2, r3, r4, r5, ip, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
880: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
884: e302000c movw r0, #8204 ; 0x200c
888: e7900004 ldr r0, [r0, r4]
88c: e1b00b00 lsls r0, r0, #22
890: e1b00b20 lsrs r0, r0, #22
894: e1b05000 movs r5, r0
if(id_spin<32)
898: e3550020 cmp r5, #32
89c: 2a000000 bcs 8a4 <irqHandler+0x2c>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
8a0: eafffffe b 8a0 <irqHandler+0x28>
}
else
{
(pFuncIrq[id_spin-32])();
8a4: e59f0010 ldr r0, [pc, #16] ; 8bc <.text_8>
8a8: e1b01105 lsls r1, r5, #2
8ac: e0910000 adds r0, r1, r0
8b0: e5100080 ldr r0, [r0, #-128] ; 0x80
8b4: e12fff30 blx r0
}
}
8b8: e8fd903f ldm sp!, {r0, r1, r2, r3, r4, r5, ip, pc}^
Cortex A7 PUSH log,它只是压入7个寄存器,所以32位对齐就可以了
关注 link 是日志信息: