Save/restore IRQ registers in GNU C
2005-10-25 by Guillermo Prandi
Hi, all!
First of all I want to thank everybody in this group. The amount and
quality of help I'm receiving from you guys is extraordinary. I
sincerely hope I can contribute helping others in due time.
I am doing some IRQ compilation tests with GCC and the __attribute__
((interrupt("IRQ")) syntax. Apparently the code doesn't seem to
save/restore all the registers I expected. In particular, it doesn't
seem to save spsr. Also, only general registers r1-r4 are saved
before calling an external function. I have the following questions:
* Saving spsr is only needed for reentrant IRQs?
* Perhaps saving only r1-r4 is a convention, and functions should
always save by themselves any other general registers they may use?
* Should I worry or this is perfectly normal and *safe*?
Thanks in advance.
Guille
void Uart0Service(void) __attribute__ ((interrupt("IRQ"));
void Uart0Service(void)
{
18f0: e24ee004 sub lr, lr, #4 ; 0x4
18f4: e92d500f stmdb sp!, {r0, r1, r2, r3, ip, lr}
unsigned char temp_id;
temp_id = U0IIR;
18f8: e3a03903 mov r3, #49152 ; 0xc000
18fc: e283328e add r3, r3, #-536870904 ; 0xe0000008
1900: e5d32000 ldrb r2, [r3]
switch(temp_id & IDENT_MASK) {
1904: e202200e and r2, r2, #14 ; 0xe
case DATA_AVAILABLE:
case DATA_TIMEOUT:
receive();
break;
case TRANSMIT_AVAILABLE:
transmit();
default:
break;
}
/* case DATA_AVAILABLE */
1908: e3520004 cmp r2, #4 ; 0x4
190c: 0a000005 beq 1928 <Uart0Service+0x38>
/* case DATA_TIMEOUT */
1910: e352000c cmp r2, #12 ; 0xc
1914: 0a000003 beq 1928 <Uart0Service+0x38>
/* case [not] TRANSMIT_AVAILABLE */
1918: e3520002 cmp r2, #2 ; 0x2
191c: 18fd900f ldmneia sp!, {r0, r1, r2, r3, ip, pc}^
1920: ebfffa69 bl 2cc <transmit>
1924: e8fd900f ldmia sp!, {r0, r1, r2, r3, ip, pc}^
1928: ebfffa75 bl 304 <receive>
192c: e8fd900f ldmia sp!, {r0, r1, r2, r3, ip, pc}^
}
Shouldn't this code also save spsr? Or perhaps this is only needed
for reentrant IRQs?
Guille