Next: Zero Length, Previous: Fixed-Point, Up: C Extensions
As an extension, the GNU C compiler supports named address spaces as defined in the N1275 draft of ISO/IEC DTR 18037. Support for named address spaces in GCC will evolve as the draft technical report changes. Calling conventions for any target might also change. At present, only the AVR, SPU, M32C, and RL78 targets support address spaces other than the generic address space.
Address space identifiers may be used exactly like any other C type
qualifier (e.g., const
or volatile
). See the N1275
document for more details.
On the AVR target, there are several address spaces that can be used
in order to put read-only data into the flash memory and access that
data by means of the special instructions LPM
or ELPM
needed to read from flash.
Per default, any data including read-only data is located in RAM (the generic address space) so that non-generic address spaces are needed to locate read-only data in flash memory and to generate the right instructions to access this data without using (inline) assembler code.
__flash
__flash
qualifier will locate data in the
.progmem.data
section. Data will be read using the LPM
instruction. Pointers to this address space are 16 bits wide.
__flash1
__flash2
__flash3
__flash4
__flash5
.progmem
N.data
where N refers to
address space __flash
N.
The compiler will set the RAMPZ
segment register approptiately
before reading data by means of the ELPM
instruction.
__memx
RAMPZ
set according to the high byte of the address.
Objects in this address space will be located in .progmem.data
.
Example
char my_read (const __flash char ** p) { /* p is a pointer to RAM that points to a pointer to flash. The first indirection of p will read that flash pointer from RAM and the second indirection reads a char from this flash address. */ return **p; } /* Locate array[] in flash memory */ const __flash int array[] = { 3, 5, 7, 11, 13, 17, 19 }; int i = 1; int main (void) { /* Return 17 by reading from flash memory */ return array[array[i]]; }
For each named address space supported by avr-gcc there is an equally named but uppercase built-in macro defined. The purpose is to facilitate testing if respective address space support is available or not:
#ifdef __FLASH const __flash int var = 1; int read_i (void) { return i; } #else #include <avr/pgmspace.h> /* From avr-libc */ const int var PROGMEM = 1; int read_i (void) { return (int) pgm_read_word (&i); } #endif /* __FLASH */
Notice that attribute progmem
locates data in flash but
accesses to these data will read from generic address space, i.e.
from RAM,
so that you need special accessors like pgm_read_byte
from avr-libc.
Limitations and caveats
__flash
or __flash
N address spaces
will show undefined behaviour. The only address space that
supports reading across the 64 KiB flash segment boundaries is
__memx
.
__flash
N address spaces
you will have to arrange your linker skript to locate the
.progmem
N.data
sections according to your needs.
const
, i.e. as read-only data.
This still applies if the data in one of these address
spaces like software version number or calibration lookup table are intended to
be changed after load time by, say, a boot loader. In this case
the right qualification is const
volatile
so that the compiler
must not optimize away known values or insert them
as immediates into operands of instructions.
extern const __memx char foo; const __memx void *pfoo = &foo;
The code will throw an assembler warning and the high byte of
pfoo
will be initialized with 0
, i.e. the
initialization will be as if foo
was located in the first
64 KiB chunk of flash.
On the M32C target, with the R8C and M16C cpu variants, variables
qualified with __far
are accessed using 32-bit addresses in
order to access memory beyond the first 64 Ki bytes. If
__far
is used with the M32CM or M32C cpu variants, it has no
effect.
On the RL78 target, variables qualified with __far
are accessed
with 32-bit pointers (20-bit addresses) rather than the default 16-bit
addresses. Non-far variables are assumed to appear in the topmost
64 KiB of the address space.
On the SPU target variables may be declared as
belonging to another address space by qualifying the type with the
__ea
address space identifier:
extern int __ea i;
When the variable i
is accessed, the compiler will generate
special code to access this variable. It may use runtime library
support, or generate special machine instructions to access that address
space.