Skip to Main Content Skip to Footer Navigation

Sorry, your browser is not supported. We recommend upgrading your browser. We have done our best to make all the documentation and resources available on old versions of Internet Explorer, but vector image support and the layout may not be optimal. Technical documentation is available as a PDF Download.

You copied the Doc URL to your clipboard.

System register access

Special register intrinsics

Intrinsics are provided to read and write system and coprocessor registers, collectively referred to as special register.

uint32_t __arm_rsr(const char *special_register);

Reads a 32-bit system register.

uint64_t __arm_rsr64(const char *special_register);

Reads a 64-bit system register.

void* __arm_rsrp(const char *special_register);

Reads a system register containing an address.

float __arm_rsrf(const char *special_register);

Reads a 32-bit coprocessor register containing a floating point value.

double __arm_rsrf64(const char *special_register);

Reads a 64-bit coprocessor register containing a floating point value.

void __arm_wsr(const char *special_register, uint32_t value);

Writes a 32-bit system register.

void __arm_wsr64(const char *special_register, uint64_t value);

Writes a 64-bit system register.

void __arm_wsrp(const char *special_register, const void *value);

Writes a system register containing an address.

void __arm_wsrf(const char *special_register, float value);

Writes a floating point value to a 32-bit coprocessor register.

void __arm_wsrf64(const char *special_register, double value);

Writes a floating point value to a 64-bit coprocessor register.

Special register designations

The special_register parameter must be a compile time string literal. This means that the implementation can determine the register being accessed at compile-time and produce the correct instruction without having to resort to self-modifying code. All register specifiers are case-insensitive (so “apsr” is equivalent to “APSR”). The string literal should have one of the forms described below.

AArch32 32-bit coprocessor register

When specifying a 32-bit coprocessor register to __arm_rsr, __arm_rsrp, __arm_rsrf, __arm_wsr, __arm_wsrp, or __arm_wsrf:

cp<coprocessor>:<opc1>:c<CRn>:c<CRm>:<opc2>

Or (equivalently):

p<coprocessor>:<opc1>:c<CRn>:c<CRm>:<opc2>

Where:

  • <coprocessor> is a decimal integer in the range [0, 15]
  • <opc1>, <opc2> are decimal integers in the range [0, 7]
  • <CRn>, <CRm> are decimal integers in the range [0, 15].

The values of the register specifiers will be as described in [ARMARM] or the Technical Reference Manual (TRM) for the specific processor.

So to read MIDR:

unsigned int midr = __arm_rsr("cp15:0:c0:c0:0");

ACLE does not specify predefined strings for the system coprocessor register names documented in the Arm Architecture Reference Manual (for example “MIDR”).

AArch32 32-bit system register

When specifying a 32-bit system register to __arm_rsr, __arm_rsrp, __arm_wsr, or __arm_wsrp, one of:

  • The values accepted in the spec_reg field of the MRS instruction [ARMARM] (B6.1.5), for example CPSR.
  • The values accepted in the spec_reg field of the MSR (immediate) instruction [ARMARM] (B6.1.6).
  • The values accepted in the spec_reg field of the VMRS instruction [ARMARM] (B6.1.14), for example FPSID.
  • The values accepted in the spec_reg field of the VMSR instruction [ARMARM] (B6.1.15), for example FPSCR.
  • The values accepted in the spec_reg field of the MSR and MRS instructions with virtualization extensions [ARMARM] (B1.7), for example ELR_Hyp.
  • The values specified in Special register encodings used in Armv7-M system instructions. [ARMv7M] (B5.1.1), for example PRIMASK.

AArch32 64-bit coprocessor register

When specifying a 64-bit coprocessor register to __arm_rsr64, __arm_rsrf64, __arm_wsr64, or __arm_wsrf64:

cp<coprocessor>:<opc1>:c<CRm>

Or (equivalently):

p<coprocessor>:<opc1>:c<Rm>

Where:

  • <coprocessor> is a decimal integer in the range [0, 15]
  • <opc1> is a decimal integer in the range [0, 7]
  • <CRm> is a decimal integer in the range [0, 15]

AArch64 system register

When specifying a system register to __arm_rsr, __arm_rsr64, __arm_rsrp, __arm_wsr, __arm_wsr64 or __arm_wsrp:

"o0:op1:CRn:CRm:op2"

Where:

  • <o0> is a decimal integer in the range [0, 1]
  • <op1>, <op2> are decimal integers in the range [0, 7]
  • <CRm>, <CRn> are decimal integers in the range [0, 15]

AArch64 processor state field

When specifying a processor state field to __arm_rsr, __arm_rsp, __arm_wsr, or __arm_wsrp, one of the values accepted in the pstatefield of the MSR (immediate) instruction [ARMARMv8] (C5.6.130).

Coprocessor Intrinsics

AArch32 coprocessor intrinsics

In the intrinsics below coproc, opc1, opc2, CRn and CRd are all compile time integer constants with appropriate values as defined by the coprocessor for the intended architecture.

The argument order for all intrinsics is the same as the operand order for the instruction as described in the Arm Architecture Reference Manual, with the exception of MRC/ MRC2/ MRRC/MRRC2 which omit the Arm register arguments and instead returns a value and MCRR/MCRR2 which accepts a single 64 bit unsigned integer instead of two 32-bit unsigned integers.

AArch32 Data-processing coprocessor intrinsics

Intrinsics are provided to create coprocessor data-processing instructions as follows:

Intrinsics Equivalent Instruction
void __arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2) CDP coproc, opc1, CRd, CRn, CRm, opc2
void __arm_cdp2(coproc, opc1, CRd, CRn, CRm, opc2) CDP2 coproc, opc1, CRd, CRn, CRm, opc2

AArch32 Memory coprocessor transfer intrinsics

Intrinsics are provided to create coprocessor memory transfer instructions as follows:

Intrinsics Equivalent Instruction
void __arm_ldc(coproc, CRd, const void* p) LDC coproc, CRd, […]
void __arm_ldcl(coproc, CRd, const void* p) LDCL coproc, CRd, […]
void __arm_ldc2(coproc, CRd, const void* p) LDC2 coproc, CRd, […]
void __arm_ldc2l(coproc, CRd, const void* p) LDC2L coproc, CRd, […]
void __arm_stc(coproc, CRd, void* p) STC coproc, CRd, […]
void __arm_stcl(coproc, CRd, void* p) STCL coproc, CRd, […]
void __arm_stc2(coproc, CRd, void* p) STC2 coproc, CRd, […]
void __arm_stc2l(coproc, CRd, void* p) STC2L coproc, CRd, […]

AArch32 Integer to coprocessor transfer intrinsics

Intrinsics are provided to map to coprocessor to core register transfer instructions as follows:

Intrinsics Equivalent Instruction
void __arm_mcr(coproc, opc1, uint32_t value, CRn, CRm, opc2) MCR coproc, opc1, Rt, CRn, CRm, opc2
void __arm_mcr2(coproc, opc1, uint32_t value, CRn, CRm, opc2) MCR2 coproc, opc1, Rt, CRn, CRm, opc2
uint32_t __arm_mrc(coproc, opc1, CRn, CRm, opc2) MRC coproc, opc1, Rt, CRn, CRm, opc2
uint32_t __arm_mrc2(coproc, opc1, CRn, CRm, opc2) MRC2 coproc, opc1, Rt, CRn, CRm, opc2
void __arm_mcrr(coproc, opc1, uint64_t value, CRm) MCRR coproc, opc1, Rt, Rt2, CRm
void __arm_mcrr2(coproc, opc1, uint64_t value, CRm) MCRR2 coproc, opc1, Rt, Rt2, CRm
uint64_t __arm_mrrc(coproc, opc1, CRm) MRRC coproc, opc1, Rt, Rt2, CRm
uint64_t __arm_mrrc2(coproc, opc1, CRm) MRRC2 coproc, opc1, Rt, Rt2, CRm

The intrinsics __arm_mcrr/__arm_mcrr2 accept a single unsigned 64-bit integer value instead of two 32-bit integers. The low half of the value goes in register Rt and the high half goes in Rt2. Likewise for __arm_mrrc/__arm_mrrc2 which return an unsigned 64-bit integer.

Unspecified behavior

ACLE does not specify how the implementation should behave in the following cases:

  • When merging multiple reads/writes of the same register.
  • When writing to a read-only register, or a register that is undefined on the architecture being compiled for.
  • When reading or writing to a register which the implementation models by some other means (this covers – but is not limited to – reading/writing cp10 and cp11 registers when VFP is enabled, and reading/writing the CPSR).
  • When reading or writing a register using one of these intrinsics with an inappropriate type for the value being read or written to.
  • When writing to a coprocessor register that carries out a “System operation”.
  • When using a register specifier which doesn’t apply to the targetted architecture.
Was this page helpful? Yes No