This is the mail archive of the crossgcc@sources.redhat.com mailing list for the crossgcc project.
See the CrossGCC FAQ for lots more information.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Philip Blundell wrote: > > In message <3BF105C8.E4A7451@luukku.com>, Kai Ruottu writes: > > I wrote somehow unclear, but my conclusion was the opposite... I have the > >examples from Atmel for the assembly wrappers and there are quite a lot > >extra things to do like in the prologue : > > > >;- Adjust and save LR_irq mode in IRQ stack > > sub r14, r14, #4 > > stmfd sp!, {r14} > > > >;- Save SPSR and r0 in IRQ stack > > mrs r14, SPSR > > stmfd sp!, {r0, r14} > > None of this stuff is specific to AT91, nor is it strictly necessary. It all > depends on what environment you want your ISR to run in. If you need the > level of control that means you want to switch processor modes and stuff, you > should probably be using an assembler veneer rather than trying to persuade > the compiler to generate this code. I'm still a newbie with ARM, but what I have read, says that the link-register (one of its incarnations) takes the return address when the interrupt happens, it is not pushed onto the stack automatically as happens with many other CPUs. Meanwhile the link-register will be allocated as a workspace in functions... Perhaps the stack can be common in all modes but somehow the link-register which has the return address should be saved onto the stack or changed into some other incarnation in another register bank. And restored into 'pc' somehow in the epilogue. And all the other workspace/scratch registers used in the ISR should be saved and restored too. My first tries with the gcc-3.0.2 implementation have showed the current implementation being weird... > >From a quick look at the output from gcc-3.0 it seems to be doing roughly the > right thing. If you think there are bugs, perhaps you could post a testcase > that illustrates them. Ok, here is one, taken from some 'alien' world : ------------------ clip -------------------------------- #include <stdio.h> #define PBDR (*(volatile char *) (0xffffe0)) #define ITU_TSR0 (*(volatile char *) (0xffffe4)) #define ISR_FUNC __attribute__((interrupt)) int count; void ISR_FUNC handle_intr(void) { count++; if (count == 400) { PBDR ^= 0x01; count = 0; } ITU_TSR0 &= 0xFE; PBDR ^= 0x02; PBDR &= 0xFD; } int main(void) { static int i; for (i=0; i < 1000000; i++) puts("Just waiting...\n"); return 0; } ------------------ clip -------------------------------- One could claim that changing bytes in memory never happens in ARM, but I didn't know it when trying this, so the previous code produces now with my fixed gcc-3.0.2, which saves/restores the 'ip' and 'lr' too if they are used in the ISR, the following using '-Os' as the optimization : ------------------ clip -------------------------------- @ Generated by gcc 3.0.2 for ARM/elf .file "isr_demo1.c" .text .align 2 .global handle_intr .type handle_intr,function handle_intr: @ Interrupt Service Routine. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, current_function_anonymous_args = 0 stmfd sp!, {r0, r1, r2, r3, ip, lr} ldr r1, .L3 ldr r3, [r1, #0] ldr r0, .L3+4 add r3, r3, #1 str r3, [r1, #0] cmp r3, #400 mov ip, r0 ldreqb r3, [ip, #0] moveq r2, #0 eoreq r3, r3, #1 streq r2, [r1, #0] ldr lr, .L3+8 streqb r3, [ip, #0] ldrb r3, [lr, #0] and r3, r3, #254 strb r3, [lr, #0] ldrb r3, [r0, #0] eor r3, r3, #2 strb r3, [r0, #0] ldrb r3, [r0, #0] and r3, r3, #253 strb r3, [r0, #0] ldmfd sp!, {r0, r1, r2, r3, ip, lr} subs pc, lr, #4 .L4: .align 2 .L3: .word count .word 16777184 .word 16777188 .Lfe1: .size handle_intr,.Lfe1-handle_intr .bss .align 2 i.0: .space 4 .section .rodata .align 2 .LC0: .ascii "Just waiting...\n\000" .text .align 2 .global main .type main,function main: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, current_function_anonymous_args = 0 mov ip, sp stmfd sp!, {fp, ip, lr, pc} sub fp, ip, #4 bl __gccmain ldr r3, .L12 mov r2, #0 str r2, [r3, #0] .L9: ldr r0, .L12+4 bl puts ldr r3, .L12 ldr r2, [r3, #0] ldr r1, .L12+8 add r2, r2, #1 cmp r2, r1 str r2, [r3, #0] ble .L9 mov r0, #0 ldmea fp, {fp, sp, pc} .L13: .align 2 .L12: .word i.0 .word .LC0 .word 999999 .Lfe2: .size main,.Lfe2-main .comm count, 4 @ 4 ------------------ clip -------------------------------- The original gcc-3.0.2 didn't save/restore the 'ip' and 'lr' (this is my memory about it)... Then I found out that there could be an additional '(IRQ)', '(FIQ)' etc. in the attribute, and 'nothing', as in the previous, would lead to the same as the '(IRQ)'. But adding one of these causes only the 'lr' being saved in the epilogue and it seems that the function will then be handled as 'normal'. So the following doesn't work for some reason : ------------------ clip -------------------------------- #define ISR_FUNC __attribute__((interrupt (IRQ))) void ISR_FUNC handle_intr(void) { ..... } ------------------ clip -------------------------------- > What "overwriting of lr" are you referring to? If the 'lr' is not saved in the ISR-epilogue and it is used in the ISR as a workspace, my thought is that the following 'return instruction' doesn't work: subs pc, lr, #4 Perhaps this isn't the case, only the 'ip' will be destroyed now, anyway here are my fixes for the 'ip' and 'lr' save/restore in ISR for gcc-3.0.2: ------------------ clip -------------------------------- *** arm.bak Tue Nov 14 14:50:02 2001 --- arm.c Tue Nov 14 14:50:02 2001 *************** *** 6983,6989 **** /* Decide if we need to save the link register. Interrupt routines have their own banked link register, so they never need to save it. ! Otheriwse if we do not use the link register we do not need to save it. If we are pushing other registers onto the stack however, we can save an instruction in the epilogue by pushing the link register now and then popping it back into the PC. This incurs extra memory --- 6983,6989 ---- /* Decide if we need to save the link register. Interrupt routines have their own banked link register, so they never need to save it. ! Otherwise if we do not use the link register we do not need to save it. If we are pushing other registers onto the stack however, we can save an instruction in the epilogue by pushing the link register now and then popping it back into the PC. This incurs extra memory *************** *** 6995,7000 **** --- 6995,7007 ---- && optimize_size && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL))) save_reg_mask |= 1 << LR_REGNUM; + else if (IS_INTERRUPT (func_type)) + { + if (regs_ever_live [IP_REGNUM]) + save_reg_mask |= 1 << IP_REGNUM; + if (regs_ever_live [LR_REGNUM]) + save_reg_mask |= 1 << LR_REGNUM; + } if (cfun->machine->lr_save_eliminated) save_reg_mask &= ~ (1 << LR_REGNUM); ------------------ clip -------------------------------- The clause in the comment: Interrupt routines have their own banked link register, so they never need to save it. sounds more than weird when the link-register is one of the registers to be used as workspace... Or is the 'lr' in the opcode : subs pc, lr, #4 (subscribe #4 from 'lr' and put the result in 'pc' is my interpretation about this...) not the same as used as workspace in those opcodes like: ldr lr, .L3+8 in the generated code? A newbie like me assumes them being the same 'lr' from the same register bank, but perhaps this is not the case... Cheers, Kai ------ Want more information? See the CrossGCC FAQ, http://www.objsw.com/CrossGCC/ Want to unsubscribe? Send a note to crossgcc-unsubscribe@sourceware.cygnus.com
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |