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]

Re: ISR-support in ARM


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]