Keil Logo Arm Logo

Technical Support

On-Line Manuals

Compiler User Guide

Conventions and Feedback Overview of the Compiler Getting Started with the Compiler Compiler Features Compiler intrinsics Performance benefits of compiler intrinsics ARM assembler instruction intrinsics supported by Generic intrinsics supported by the compiler Compiler intrinsics for controlling IRQ and FIQ in Compiler intrinsics for inserting optimization bar Compiler intrinsics for inserting native instructi Compiler intrinsics for Digital Signal Processing European Telecommunications Standards Institute (E Compiler support for European Telecommunications S Overflow and carry status flags for C and C++ code Texas Instruments (TI) C55x intrinsics for optimiz Compiler support for accessing registers using nam Pragmas recognized by the compiler Compiler and processor support for bit-banding Compiler type attribute, __attribute__((bitband)) --bitband compiler command-line option How the compiler handles bit-band objects placed o Compiler support for thread-local storage Compiler eight-byte alignment features Using compiler and linker support for symbol versi PreCompiled Header (PCH) files Automatic PreCompiled Header (PCH) file processing PreCompiled Header (PCH) file processing and the h PreCompiled Header (PCH) file creation requirement Compilation with multiple PreCompiled Header (PCH) Obsolete PreCompiled Header (PCH) files Manually specifying the filename and location of a Selectively applying PreCompiled Header (PCH) file Suppressing PreCompiled Header (PCH) file processi Message output during PreCompiled Header (PCH) pro Performance issues with PreCompiled Header (PCH) f Default compiler options that are affected by opti Compiler Coding Practices Compiler Diagnostic Messages Using the Inline and Embedded Assemblers of the AR

Compiler support for accessing registers using named register variables

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 __asm keyword. The __asm keyword takes one parameter, a character string, that names the register. For example, the following declaration declares R0 as a named register variable for the register r0:

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 Q in the APSR.

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 --cpu=7-M:

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 MCR instruction, look up the instruction syntax for this instruction and use this syntax when you declare your variable. See Example 5.

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, PMCR is declared as a register variable of type unsigned int, that is associated with the cp15 coprocessor, with CRn = c9, CRm = c12, opcode1 = 0, and opcode2 = 0 in an MCR or MRC instruction. The MCR encoding in the disassembly corresponds with the register variable declaration.

The physical coprocessor register is specified with a combination of the two register numbers, CRn and CRm, and two opcode numbers. This maps to a single physical register.

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

Copyright © 2007-2008, 2011-2012 ARM. All rights reserved.ARM DUI 0375D
Non-ConfidentialID062912

Keil logo

Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.