[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-chat] how to safely use register asm("r2")?
From: |
Erik Christiansen |
Subject: |
Re: [avr-chat] how to safely use register asm("r2")? |
Date: |
Sat, 16 May 2015 19:43:54 +1000 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On 13.05.15 15:49, Britton Kerin wrote:
> I've got some code with tight timing that works at 10MHz
> only if I register lock some globals as described here:
> http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_regbind
>
> I'm using registers r2 through r5. The FAQ seems to be saying
> that this is safe in the above faq_regbind section, and also in
> http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage
>
> >From that last item, I conclude that this consideration from the GCC manual:
>
> A function that can alter the value of a global register variable
> cannot safely be called from a function compiled without this variable,
> because it could clobber the value the caller expects to find there on
> return. Therefore, the function that is the entry point into the part of
> the program that uses the global register variable must explicitly save
> and restore the value that belongs to its caller.
>
> Doesn't apply for register r2 through r5 on AVR.
On the contrary, reading it carefully, I'd say it applies universally.
If the global is not to be overwritten, all code modules must either
regbind, or push/pop the register to preserve it. The second sentence of
the quote, however, points to your need to preserve the caller's r2 at
the start of your assembler function, rather than describing protection
of your global variable. (Shouldn't be needed with a universal regbind,
I'd guess.)
...
> It also works (at higher CPU speeds) if I don't declare the globals with
> register locking, so I'm guessing that is somehow the problem. The FAQ says:
>
> Extreme care should be taken that the entire application is compiled with
> a consistent set of register-allocated variables, including possibly used
> library functions.
>
> What is the best way to do this? Is it safe to assume that avr-libc doesn't
> use r2 through r7, or correctly saves and restores them if it uses them
> from assembly?
It is never safe to assume. ;-)
Simple observation confirms the fallacy of the first assumption:
$ avr-objdump -d /usr/lib/avr/lib/libc.a > /tmp/libc
$ egrep '\<r2\>' /tmp/libc | more
1ac: 28 2e mov r2, r24
1f4: 20 2e mov r2, r16
204: 82 2d mov r24, r2
21c: 2f 80 ldd r2, Y+7 ; 0x07
220: 20 0e add r2, r16
23c: e2 2c mov r14, r2
240: 42 2c mov r4, r2
2fc: 82 2c mov r8, r2
366: 2e 2c mov r2, r14
36a: 24 18 sub r2, r4
376: 24 16 cp r2, r20
37c: 42 2d mov r20, r2
3ce: 82 15 cp r24, r2
3d4: 82 2d mov r24, r2
a: 26 2e mov r2, r22
1b2: 21 14 cp r2, r1
1c2: e2 2d mov r30, r2
1d6: e2 2d mov r30, r2
a: 26 2e mov r2, r22
1d0: 21 14 cp r2, r1
1de: a2 2d mov r26, r2
1f0: e2 2d mov r30, r2
4: 2d 92 st X+, r2
50: 2d 90 ld r2, X+
172: 26 2e mov r2, r22
174: 22 22 and r2, r18
1a8: 25 2e mov r2, r21
1aa: 22 2a or r2, r18
1b0: 23 fc sbrc r2, 3
1d2: 27 fc sbrc r2, 7
1d6: 27 fe sbrs r2, 7
A quick repeat shows that avrlibc makes heavy use of all of r2 - r7.
And since there are no push/pop pairs in there, then the second
assumption could be no better than the first. What you need to check is
whether avr-gcc pushes the clobber list. My guess is that part of
compiler optimisation is to preserve only the registers which are
clobbered. It sounds like you wish to be more certain than a guess.
A response to that question would be more likely on the avr-gcc mailing
list, since it is much more active. But you can answer it yourself by
calling some libc functions, disassembling the object file as above,
and checking that any r2 - r17 registers used are preserved.
Erik