|
|||||||||||
|
Technical Support On-Line Manuals Compiler User Guide |
Compiler support for accessing registers using named register variables
The compiler enables you to access registers of an ARM architecture-based processor using named register variables. Named register variables are declared by combining the register keyword
with the
register int R0 __asm("r0");
You can declare named register variables as global variables. You can declare some, but not all, named register variables as local variables. In general, do not declare Vector Floating-Point (VFP) registers and core registers as local variables. Do not declare caller-save registers, such as R0, as local variables. (Caller-save registers are registers that the caller must save the values of, if it wants the values after the subroutine completes.) Your program might still compile if you declare these locally, but you risk unexpected runtime behavior if you do this. A typical use of named register variables is to access bits
in the Application Program Status Register (APSR).
Example 3-3 shows the use of named register variables to set the
saturation flag Example 2. Setting bits in the APSR using a named register variable
#ifndef __BIG_ENDIAN // bitfield layout of APSR is sensitive to endianness
typedef union
{
struct
{
int mode:5;
int T:1;
int F:1;
int I:1;
int _dnm:19;
int Q:1;
int V:1;
int C:1;
int Z:1;
int N:1;
} b;
unsigned int word;
} PSR;
#else /* __BIG_ENDIAN */
typedef union
{
struct
{
int N:1;
int Z:1;
int C:1;
int V:1;
int Q:1;
int _dnm:19;
int I:1;
int F:1;
int T:1;
int mode:5;
} b;
unsigned int word;
} PSR;
#endif /* __BIG_ENDIAN */
/* Declare PSR as a register variable for the "apsr" register */
register PSR apsr __asm("apsr");
void set_Q(void)
{
apsr.b.Q = 1;
}
See also Example 3. Example 3. Clearing the Q flag in the APSR using a named register variable
register unsigned int _apsr __asm("apsr");
__forceinline void ClearQFlag(void)
{
_apsr = _apsr & ~0x08000000; // clear Q flag
}
Disassembly: ClearQFlag MRS r0,APSR ; formerly CPSR BIC r0,r0,#0x80000000 MSR APSR_nzcvq,r0; formerly CPSR_f BX lr See also Example 4. Example 4. Setting up stack pointers using named register variables
register unsigned int _control __asm("control");
register unsigned int _msp __asm("msp");
register unsigned int _psp __asm("psp");
void init(void)
{
_msp = 0x30000000; // set up Main Stack Pointer
_control = _control | 3; // switch to User Mode with Process Stack
_psp = 0x40000000; // set up Process Stack Pointer
}
Disassembly, compiled using init MOV r0,0x30000000 MSR MSP,r0 MRS r0,CONTROL ORR r0,r0,#3 MSR CONTROL,r0 MOV r0,#0x40000000 MSR PSP,r0 BX lr You can also use named register variables to access registers
within a coprocessor. The string syntax within the declaration corresponds
to how you intend to use the variable. For example, to declare a
variable that you intend to use with the Example 5. Setting bits in a coprocessor register using a named register variable
register unsigned int PMCR __asm(”cp15:0:c9:c12:0”);
__inline void __reset_cycle_counter(void)
{
PMCR = 4;
}
Disassembly:
__reset_cycle_counter PROC
MOV r0,#4
MCR p15,#0x0,r0,c9,c12,#0 ; move from r0 to c9
BX lr
ENDP
In Example 5, The physical coprocessor register is specified with a combination
of the two register numbers, The same principle applies if you want to manipulate individual bits in a register, but you write normal variable arithmetic in C, and the compiler does a read-modify-write of the coprocessor register. See Example 6. Example 6. Manipulating bits in a coprocessor register using a named register variable
register unsigned int SCTLR __asm(”cp15:0:c1:c0:0”);
/* Set bit 11 of the system control register */
void enable_branch_prediction(void)
{
SCTLR |= (1 << 11);
}
Disassembly:
__enable_branch_prediction PROC
MRC p15,#0x0,r0,c1,c0,#0
ORR r0,r0,#0x800
MCR p15,#0x0,r0,c1,c0,#0
BX lr
ENDP
| ||||||||||
|
|||||||||||