User guide

Peripheral locations should not be accessed using __packed structs (where unaligned members are allowed and
there is no internal padding), or using C bitfields. This is because it is not possible to control the number and type of
memory access that is being performed by the compiler.
The result is code that is non-portable, has undesirable side effects, and will not work as intended. The
recommended way of accessing peripherals is through explicit use of architecturally-defined types such as int,
short, char on their natural alignment.
Using a pointer to struct/array
struct PortRegs {
unsigned short ctrlreg; /* offset 0 */
unsigned short dummy1;
unsigned short datareg; /* offset 4 */
unsigned short dummy2;
unsigned int data32reg; /* offset 8 */
};
volatile struct PortRegs *iospace =
(struct PortRegs *)0x40000000;
x = iospace->ctrlreg;
iospace->ctrlreg = newval;
The pointer can be either local or global. If you want the pointer to be global in order to avoid the base pointer being
reloaded after function calls, make iospace a constant pointer to the struct by changing its definition to:
volatile struct PortRegs * const iospace =
(struct PortRegs *)0x40000000;
6.9.4 Using scatter loading
The variable, array, or struct must be declared in a file on its own. When it is compiled, the object code for this file
contains only data. This data can be placed at a specified address using the ARM scatter-loading mechanism. This is
the recommended method for placing regions at required locations in the memory map.
Create a file, for example iovar.c that contains a declaration of the variable, array, or struct. For example:
volatile unsigned short u16_IORegs[20];
or
struct{
volatile unsigned reg1;
volatile unsigned reg2;
} mem_mapped_reg;
Create a scatter-load description file, called for example scatter.scf, containing the code in Example 6-14.
Example 6-14 Sample file
ALL 0x8000 ; one load region ALL at 0x8000
{
ALL 0x8000 ; by default, everything goes into this region
{
* (+RO,+RW,+ZI)
}
IO 0x40000000 UNINIT ; register variables go here
; initial zeros are not written
{
iovar.o (+ZI) ; a single module is selected by name
}
}
The scatter-load description file must be specified to the linker using the -scatter scatter.scf command-line
option. The UNINIT keyword in the description file indicates that the ZI region will not be initialized with zeros when
the application is reset. If you want the peripheral registers to have zero written to them on reset, omit the UNINIT
keyword. The scatter-load description file creates two different regions in your image (ALL and IO). The zero-init
area from iovar.o (containing your array or struct) goes into the IO area located at 0x40000000. All code (RO)
and data areas (RW and ZI) from other object files go into the ALL region that starts at 0x8000.
If you have more than one group of variables (more than one set of memory mapped registers) you must define each
group of variables as a separate execution region (they could, however, all lie within a single load region). Each
group of variables must be defined in a separate module.
Writing Code for ROM
Copyright ?1999 2001 ARM Limited 6-26