You copied the Doc URL to your clipboard.

Named register variables

The compiler enables you to access registers of an ARM architecture-based processor or coprocessor using named register variables.

register type var-name __asm( reg );



is the type of the named register variable.

Any type of the same size as the register being named can be used in the declaration of a named register variable. The type can be a structure, but bitfield layout is sensitive to endianness.


is the name of the named register variable.


is a character string denoting the name of a register on an ARM architecture-based processor, or for coprocessor registers, a string syntax that identifies the coprocessor and corresponds with how you intend to use the variable.

Registers available for use with named register variables on ARM architecture-based processors are shown in the following table.

Table 1. Named registers available on ARM architecture-based processors
Register Character string for __asm Processors
APSR "apsr" All processors
CPSR "cpsr" All processors
BASEPRI "basepri" ARMv7-M processors
BASEPRI_MAX "basepri_max" ARMv7-M processors
CONTROL "control" ARMv6-M and ARMv7-M processors
DSP "dsp" ARMv6-M and ARMv7-M processors
EAPSR "eapsr" ARMv6-M and ARMv7-M processors
EPSR "epsr" ARMv6-M and ARMv7-M processors
FAULTMASK "faultmask" ARMv7-M processors
IAPSR "iapsr" ARMv6-M and ARMv7-M processors
IEPSR "iepsr" ARMv6-M and ARMv7-M processors
IPSR "ipsr" ARMv6-M and ARMv7-M processors
MSP "msp" ARMv6-M and ARMv7-M processors
PRIMASK "primask" ARMv6-M and ARMv7-M processors
PSP "psp" ARMv6-M and ARMv7-M processors
PSR "psr" ARMv6-M and ARMv7-M processors
r0 to r12 "r0" to "r12" All processors
r13 or sp "r13" or "sp" All processors
r14 or lr "r14" or "lr" All processors
r15 or pc "r15" or "pc" All processors


All processors, apart from Cortex-M series processors.
XPSR "xpsr" ARMv6-M and ARMv7-M processors

On targets with floating-point hardware, the registers listed in the following table are also available for use with named register variables.

Table 2. Named registers available on targets with floating-point hardware
Register Character string for __asm
FPSID "fpsid"
FPSCR "fpscr"
FPEXC "fpexc"
FPINST "fpinst"
FPINST2 "fpinst2"
FPSR "fpsr"
MVFR0 "mvfr0"
MVFR1 "mvfr1"


Some registers are not available on some architectures.


You must declare core registers as global rather than local named register variables. Your program might still compile if you declare them locally, but you risk unexpected runtime behavior if you do. There is no restriction on the scope of named register variables for other registers.


A global named register variable is global to the source file in which it is declared, not global to the program. It has no effect on other files, unless you use multifile compilation or you declare it in a header file.


Declaring a core register as a named register variable means that register is not available to the compiler for other operations. If you declare too many named register variables, code size increases significantly. In some cases, your program might not compile, for example if there are insufficient registers available to compute a particular expression.

Register usage defined by the Procedure Call Standard for the ARM Architecture (AAPCS) is not affected by declaring named register variables. For example, r0 is always used to return result values from functions even if it is declared as a named register variable.

Named register variables are a compiler-only feature. With the exception of r12, tools such as linkers do not change register usage in object files. The AAPCS reserves r12 as the inter-procedural scratch register. You must not declare r12 as a named register variable if you require its value to be preserved across function calls.


In the following example, apsr is declared as a named register variable for the "apsr" register:

register unsigned int apsr __asm("apsr");
apsr = ~(~apsr | 0x40);

This generates the following instruction sequence:

MRS r0,APSR ; formerly CPSR
BIC r0,r0,#0x40
MSR CPSR_c, r0

In the following example, PMCR is declared as a register variable associated with coprocessor cp15, with CRn = c9, CRm = c12, opcode1 = 0, and opcode2 = 0, in an MCR or an MRC instruction:

register unsigned int PMCR __asm("cp15:0:c9:c12:0");
__inline void __reset_cycle_counter(void)
    PMCR = 4;

The disassembled output is as follows:

__reset_cycle_counter PROC
    MOV    r0,#4
    MCR    p15,#0x0,r0,c9,c12,#0
    BX     lr

In the following example, cp15_control is declared as a register variable for accessing a coprocessor register. This example enables the MMU using CP15:

register unsigned int cp15_control __asm("cp15:0:c1:c0:0");
cp15_control |= 0x1;

The following instruction sequence is generated:

MRC  p15,#0x0,r0,c1,c0,#0
ORR  r0,r0,#1
MCR  p15,#0x0,r0,c1,c0,#0

The following example for Cortex-M3 declares _msp, _control and _psp as named register variables to set up stack pointers:

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

This generates the following instruction sequence:

  MOV r0,#0x30000000
  MSR MSP,r0
  ORR r0,r0,#3
  MOV r0,#0x40000000
  MSR PSP,r0
  BX lr