Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: Save/restore IRQ registers in GNU C

2005-10-25 by Guillermo Prandi

Thanks, Dave. This answers my question. I wasn't aware of the APCS, 
but I deeply suspected there was one.

Best regards,

Guille

--- In lpc2000@yahoogroups.com, "David Hawkins" <dwh@o...> wrote:
>
> 
> 
> > 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.
> > 
> 
> Hi Guille,
> 
> Let me help explain with the following (but incomplete) startup 
code:
> 
>     .global main
>     .global _start
> 	
>     /* Symbols defined by the linker script */
>     .global _etext
>     .global _data
>     .global _edata
>     .global _bss
>     .global _ebss
>     
>     /* External functions */
>     .global fiq_handler
>     .global irq_handler
> 
>     .text
>     .arm
> 
> /* ----------------------------------------------------------------
>  * Exception vectors
>  * ----------------------------------------------------------------
>  */
> _start:
>     b reset  /* reset */
>     b loop   /* undefined instruction */
>     b loop   /* software interrupt */
>     b loop   /* prefetch abort */
>     b loop   /* data abort */
>     nop      /* reserved for the bootloader checksum */
>     ldr pc, irq_addr
> 
>     /* FIQ ISR */
> fiq_isr:
>     sub   lr, lr, #4
>     stmfd sp!, {r0-r3, ip, lr}
>     bl fiq_handler
>     ldmfd sp!, {r0-r3, ip, pc}^
> 
> irq_addr: .word irq_isr
> irq_isr:
>     sub   lr, lr, #4
>     stmfd sp!, {r0-r3, ip, lr}
>     bl irq_handler
>     ldmfd sp!, {r0-r3, ip, pc}^
> 
> 
> Ok, above I define two external interrupt handlers written as
> C-functions *** without the __interrupt__ attribute ***
> 
> The FIQ handler lives at the FIQ vector address, while the IRQ
> handler is loaded into the PC, jumping it to irq_isr, which\
> in turn saves context and jumps to the irq_handler function.
> 
> The ONLY registers you need to save there are the APCS
> (ARM Procedure Calling Standard) 'scratch' registers.
> Those registers are; r0-r3, and ip. The lr you save cause
> you're calling a function.
> 
> All that the GNU compiler does is exactly that, and then
> it optimizes, i.e., if it doesn't use r0-r3, it'll remove
> them from the generated code.
> 
> The SPSR register only needs saving when nesting IRQ interrupts.
> If an FIQ interrupt occurs while processing an IRQ interrupt,
> its ok, as the FIQ mode has its own SPSR.
> 
> Cheers
> Dave
>

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.