avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] Re: assembly-c mix and interrupts


From: David Brown
Subject: [avr-gcc-list] Re: assembly-c mix and interrupts
Date: Fri, 20 Nov 2009 11:47:45 +0100
User-agent: Thunderbird 2.0.0.23 (Windows/20090812)

Julius Luukko wrote:
(note to the list: Alexander replied me off-list but I am replying to the list also)

On Thursday 19 November 2009, you wrote:
Thanks for your reply,
I understand that it is VERY important to store/restore the SREG in an
interrupt function. Can you please confirm for me that the ISR() c macro
does this for me and also, does your advice extend to functions outside the
interrupt routine? I have found reference material stating which registers
should be stored, but none of them mention the SREG in any way.


The register set is divided into "volatile" or "call-used" registers, "non-volatile" or "call-saved" registers, and fixed-function registers. This division is chosen by avr-gcc - it is not hardware dependent. When working with assembly, you can make up your own rules, but this is how things interact with C code.

When the compiler is generated code for a function, it can assume that it can do as it likes for the call-used registers, but if it uses the call-saved registers it must preserve them at the entry to the function, and restore them on exit. Similarly, it can assume that whenever it calls another function, the call-used registers will be trashed but the call-saved registers will be preserved.

R0 is used as a temporary register - individual instruction sequences will use it freely. R1 is assumed to be always 0, although some code sequences will use it temporarily (and restore it to 0 afterwards). The SREG is considered a "call-used" register.

So any function generated by the compiler, or compatible functions written in assembly by hand, can freely use the call-used registers (SREG, r18-r27, r30-r31) without preserving or restoring them. But if it wants to use the call-saved registers (r2-r17, r28-r29), it must save them on entry and restore them on exit.

An interrupt routine must also preserve any call-used registers it needs, including SREG and r0. It must also preserve the current r1 and set it to 0 before certain compiler-generated code is executed. If the interrupt routine is going to call other functions, it must preserve /all/ the call-used registers, since the other functions may trash them. On the other hand, it does not need to preserve any of the call-saved registers, as the called function will preserve these as needed.


I can't provide you with a reference but AFAIK this is done on the gcc level (which I know nothing about). The actual definition in the avr-libc source does not show it:

<http://cvs.savannah.gnu.org/viewvc/avr-libc/include/avr/interrupt.h?revision=1.25.2.1&root=avr-libc&view=markup>


(Always put links inside < and > brackets - that way email programs won't mangle them by splitting the line.)

Anyway, SREG should always be stored to the stack when using the ISR() macro. Maybe someone can provide with a reference to prove this.


It is, as you say, done at the gcc level. The provided ISR macros are wrappers that give the function the "signal" attribute, which causes gcc to preserve SREG and all the volatile call-used registers (if they are used), and to use the "rti" instruction at the end.

The compiler gets this stuff right (if it didn't, someone would have noticed before now!) - it is much easier to rely on the compiler to generate correct code here from an ISR written in C, than to try and write it by hand in assembly.

mvh.,

David



An excerpt from a C generated ISR () shows an example (I don't remember which version of gcc or avr-libc was used, this was just easily found):

00000108 <__vector_18>:
 108:   1f 92           push    r1
 10a:   0f 92           push    r0
 10c:   0f b6           in      r0, 0x3f        ; 63
 10e:   0f 92           push    r0
 110:   11 24           eor     r1, r1
 112:   8f 93           push    r24
 114:   9f 93           push    r25
 116:   ef 93           push    r30
 118:   ff 93           push    r31

SREG is memory mapped to 0x3f. As you can see, you can't push SREG directly, you must use a register for that and therefore you must push the register first.

One thing to note also in the excerpt is the clearing of r1 (eor r1, r1). If you intend to call C functions from your assembly ISR, you must do this also. This might provide you with some more information

http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

Julius

From: address@hidden
To: address@hidden
Subject: Re: [avr-gcc-list] assembly-c mix and interrupts
Date: Thu, 19 Nov 2009 15:34:16 +0200
CC: address@hidden

On Thursday 19 November 2009, darkschine wrote:
Before I continue, I would like to suggest a resolution to my problem.
I am using the ATmega328P
My assembly code follows a standard that ALL registers used are pushed
and popped from the stack. However, my assembly code does NOT store the
SREG. Could this be causing my problems?
You can do next to nothing without modifying the SREG. Why don't you add
pushing the SREG also to the stack. I wouldn't dare to not to save it.

--
Julius
_________________________________________________________________
Looking for a date? View photos of singles in your area!
http://clk.atdmt.com/NMN/go/150855801/direct/01/







reply via email to

[Prev in Thread] Current Thread [Next in Thread]