how to safely use register asm("r2")?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

how to safely use register asm("r2")?

Britton Kerin
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.

Unfortunately, I then get an issue where changing these two lines:

  uint8_t const rss = 7;
  for ( uint8_t ii = 0 ; ii < rss ; ii++ ) {

to:

  uint8_t const rss = 7;
  for ( uint8_t ii = 0 ; ii < rss + 0 ; ii++ ) {

is required for things to work.  Adding a "+ 0" to the loop test somehow
makes it work.  Hmm.

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?

_______________________________________________
AVR-chat mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-chat
Reply | Threaded
Open this post in threaded view
|

Re: how to safely use register asm("r2")?

Erik Christiansen-2
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

_______________________________________________
AVR-chat mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-chat