|
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 r31SREG 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 informationhttp://www.nongnu.org/avr-libc/user-manual/inline_asm.html JuliusFrom: 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/
[Prev in Thread] | Current Thread | [Next in Thread] |