avr-libc-dev
[Top][All Lists]
Advanced

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

Re: [avr-libc-dev] volatile in pgmspace.h ?


From: Marek Michalkiewicz
Subject: Re: [avr-libc-dev] volatile in pgmspace.h ?
Date: Tue, 17 Jun 2003 23:21:25 +0200
User-agent: Mutt/1.4i

On Tue, Jun 17, 2003 at 07:13:22PM +0000, E. Weddington wrote:
> Again, your comment about how it cannot be guaranteed that 
> gcc will keep the value of Z in between calls to the macros 
> is a strong argument against inclusion of _next() macros.

Hmm... perhaps I was not clear enough, here is an example of what
I'm talking about (enhanced core only, not tested):

/* byte read with no post-increment, easy */
#define __LPM_enhanced__(addr) ({                       \
        uint16_t __addr16 = (uint16_t)(addr);           \
        uint8_t __result;                               \
        __asm__ (                                       \
                "lpm %0,Z"                              \
                : "=r" (__result)                       \
                : "z" (__addr16)                        \
        );                                              \
        __result;                                       \
})

/* byte read with post-increment, ADDR must be a variable */
#define __LPM_postinc_enhanced__(addr) ({               \
        uint16_t __addr16 = (uint16_t)(addr);           \
        uint8_t __result;                               \
        __asm__ (                                       \
                "lpm %0,Z+"                             \
                : "=r" (__result), "=z" (__addr16)      \
                : "1" (__addr16)                        \
        );                                              \
        (addr) = (__typeof__ (addr)) __addr16;          \
        __result;                                       \
})

/* word read with no post-increment, the asm code clobbers Z
   so we need a dummy output operand to tell GCC about it */
#define __LPM_word_enhanced__(addr) ({                  \
        uint16_t __addr16 = (uint16_t)(addr);           \
        uint16_t __result;                              \
        __asm__ (                                       \
                "lpm %A0,Z+" "\n\t"                     \
                "lpm %B0,Z"                             \
                : "=r" (__result), "=z" (__addr16)      \
                : "1" (__addr16)                        \
        );                                              \
        __result;                                       \
})

/* word read with post-increment, ADDR must be a variable */
#define __LPM_word_postinc_enhanced__(addr) ({          \
        uint16_t __addr16 = (uint16_t)(addr);           \
        uint16_t __result;                              \
        __asm__ (                                       \
                "lpm %A0,Z+" "\n\t"                     \
                "lpm %B0,Z+"                            \
                : "=r" (__result), "=z" (__addr16)      \
                : "1" (__addr16)                        \
        );                                              \
        (addr) = (__typeof__ (addr)) __addr16;          \
        __result;                                       \
})

The _postinc macros expect the ADDR argument to be a variable, which
is incremented during the operation.  The "typeof" is here to avoid
warnings - the address could be a pointer, or integer.

> then you will probably run into problems as stated: it 
> cannot be guaranteed that gcc will keep the value of Z in 
> between calls.

But it can be guaranteed that GCC will keep the value of a local
variable between calls, and that variable will happen to be in Z
at the right time (forced by the "z" constraint for both input and
output of the "asm").  You could even interleave reads from two
or more different arrays in program memory, and GCC should do the
right thing (reload Z as needed).

If that looks too complicated, well it is... :) so it is up to you
if you want to implement this or not.  I just wanted to show that
it _can_ be done safely, at least I think so...

Marek





reply via email to

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