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

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

[avr-libc-dev] Re: Far addresses in flash


From: Per Arnold Blåsmo
Subject: [avr-libc-dev] Re: Far addresses in flash
Date: Thu, 02 Jun 2005 14:57:19 +0200
User-agent: Mozilla Thunderbird 1.0.2 (X11/20050317)

Carlos Lamas <address@hidden> wrote:

> Hello,
>
> This is a proposal to include a mechanism to access the true address
> of data in Flash ROM (23 bits for the AVR specification) from C code.
> The "address-of" operator '&' does not suffice with its 16 bit limited
> precision to 16 bit to read data beyond the low 64K of memory.
>
Thanks this is what I have been looking for. I need to read/write data
from/to EEPROM with address range of 24 bits. (And before anyone ask :-)
Yes, there is some ATMEL secureAVRs that needs this.)

> There are, for instance, many users programming bootloaders for the
> ATmega128 asking for a way to cleanly access data in flash from C code
> without knowing absolute data addresses at compile time.
>
> The following macro is the proposed solution:
>
>
> #ifndef __STRINGIFY
> #define __STRINGIFY(str) #str
> #endif
>
>
> #define GET_FAR_ADDRESS(var)                                    \
> ({                                                              \
>     uint32_t tmp;                                               \
>                                                                 \
>     __asm__ __volatile__(                                       \
>             "ldi    %C0, hh8(" __STRINGIFY(var) ")"   "\n\t"    \
>             "clr    %D0"                              "\n\t"    \
>         :                                                       \
>             "=d" (tmp)                                          \
>         :                                                       \
>             "0" (&var)                                          \
>     );                                                          \
>     tmp;                                                        \
> })
>
>
>
> This is a simple example of use. To test the code with true FAR (>64K)
> addresses .text section must be moved to a higher place in memory in
> the linker command.
>
>
> #include <stdint.h>
> #include <avr/pgmspace.h>
>
> static uint8_t st[] PROGMEM = "This is a flash memory string";
>
> int main (void)
> {
>     uint32_t address;
>     uint8_t c;
>
>     address = GET_FAR_ADDRESS(st);
>     address += 4 * sizeof (uint8_t);
>     while ((c = pgm_read_byte_far(address++))) {
>         foo(c);
>     }
>
>     for(;;)
>         ;
>
>     return 0;
> }
>
>
>
> COMMENTS
>
> - The overhead is minimal and it's mainly due to the 32 bit size
> operation.
>
> - 24 bit sizes guarantees the code compatibility for use in future
> devices.
>
> - hh8() is an undocumented feature but seems to give the third
> significant byte of a 32 bit data and accepts symbols, complementing
> the functionality of hi8() and lo8().
>
I have seen this to and it does what you say. Logically I would have
expected 'hl08' to be bits 16-24 and 'hh8' to be bits 25-32 of a 32 bits
data, but that does not work??

This are the one defined in tc-avr.c:

static struct exp_mod_s exp_mod[] =
{
  {"hh8",    BFD_RELOC_AVR_HH8_LDI,    BFD_RELOC_AVR_HH8_LDI_NEG,    1},
  {"pm_hh8", BFD_RELOC_AVR_HH8_LDI_PM, BFD_RELOC_AVR_HH8_LDI_PM_NEG, 0},
  {"hi8",    BFD_RELOC_AVR_HI8_LDI,    BFD_RELOC_AVR_HI8_LDI_NEG,    1},
  {"pm_hi8", BFD_RELOC_AVR_HI8_LDI_PM, BFD_RELOC_AVR_HI8_LDI_PM_NEG, 0},
  {"lo8",    BFD_RELOC_AVR_LO8_LDI,    BFD_RELOC_AVR_LO8_LDI_NEG,    1},
  {"pm_lo8", BFD_RELOC_AVR_LO8_LDI_PM, BFD_RELOC_AVR_LO8_LDI_PM_NEG, 0},
  {"hlo8",   -BFD_RELOC_AVR_LO8_LDI,   -BFD_RELOC_AVR_LO8_LDI_NEG,   0},
  {"hhi8",   -BFD_RELOC_AVR_HI8_LDI,   -BFD_RELOC_AVR_HI8_LDI_NEG,   0},
}

> - __STRINGIFY(var) could be replaced by #var and the __STRINGIFY()
> macro removed, but the nested macro sequence allows the preprocessor
> to replace the identifier 'var' when itself is also a macro.
>
> - 'var' has to be resolved at linking time as an existing symbol, i.e,
> a simple type variable name (not a constant), an array name (not an
> indexed element of the array), a struct name (not a field of the
> struct), a function identifier, a linker defined identifier,...
>
I found (http://isis.poly.edu/kulesh/stuff/src/klist/) a way yo
calculate the offset of a struct at compile time that might work also
for other purposes.

(unsigned long)(&((struct foo_bar *)0)->boo)

This gives that offset in a struct and can be added to GET_FAR_ADDRESS.

> - The input and output operands in the asm instruction are different
> sizes and both share the same storage. Particularly the output operand
> 'tmp' is bigger than the input operand '&var'. I haven't extensively
> tested this.
>
> - The & operator passes part of the job to the compiler and is valid
> for every identifier, even for array and function identifiers.
>
> - The input operand informs the compiler that the data is in use, to
> avoid used static data removal. The stringifying conversion in the
> middle of the instruction doesn't notify of the use.
>
> - The natural place for this macro should be the header pgmspace.h and
> the name... pgm_get_far_address?
>
>
> Regards
>
> -- 
> Carlos Lamas

Although I think it would have been best to have the possibilities to
support 24bits pointers in avr-gcc.

Per A.





reply via email to

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