3.1.4. Intrinsic functions

The following intrinsic functions are ARM language extensions to the ISO C and C++ specifications:

These extensions are always available.

__breakpoint() intrinsic

The __breakpoint() intrinsic enables you to include an ARM or Thumb BKPT instruction in your C or C++ code. You cannot use this intrinsic in inline assembly. The syntax for this intrinsic is:


__breakpoint(value);

value is a compile-time constant integer, and must be included. The value must be an integer in the range:

0 to 65535

if compiled as ARM code.

0 to 255

if compiled as Thumb code.

For example:


func() {
    ...
    __breakpoint(0xF02C);
    ...
}

If __breakpoint() is used on architectures that do not support the BKPT instruction, a warning is generated. If a BKPT instruction is executed on an architecture that does not support it, the undefined instruction trap is taken.

The exact location of the BKPT instruction is not guaranteed unless you specify the minimum optimization level -O0. At all other optimization levels the compiler might move, but not remove, the BKPT instruction.

For more details of the BKPT instruction, see RealView Developer Kit v2.2 Assembler Guide.

__current_pc() intrinsic

Returns the value of the program counter (PC) at the point where __current_pc() is used. The implicit prototype for this intrinsic is:


int __current_pc(void)

Note

If you have legacy source that accesses the pc register from inline assembly, see Legacy inline assembler that accesses sp, lr or pc.

__current_sp() intrinsic

Returns the value of the stack pointer (sp) at the point where __current_sp() is used. The implicit prototype for this intrinsic is:


int __current_sp(void)

Note

If you have legacy source that accesses the sp register from inline assembly, see Legacy inline assembler that accesses sp, lr or pc.

__return_address() intrinsic

Returns the value of the link register (lr) that is used to return from the current function. The implicit prototype for this intrinsic is:


int __return_address(void)

Note

If you have legacy source that accesses the lr register from inline assembly, see Legacy inline assembler that accesses sp, lr or pc.

The __return_address() intrinsic does not affect the ability of the compiler to perform optimizations, such as inlining, tail calling, and code sharing. However, the returned value reflects the optimizations performed. For more details on the optimization options, see Defining optimization criteria.

Different optimizations are applied as follows:

Inlining enabled

If a function call is inlined then the value returned by __return_address() is the return address for the function that calls the inlined function.

Inlining and tail calling disabled

If inlining and tail calling are disabled, the value returned by __return_address() is the return address of the next instruction in the calling function.

Inlining disabled and tail calling enabled

If a function call is inlined and tail calling is enabled, then the value returned by __return_address() within the called function is the return address for the caller function.

__nop() intrinsic

The __nop() intrinsic is used to insert a single NOP instruction into the instruction stream generated by the compiler. This enables you to, for example, insert a small delay between reading and writing to a memory-mapped peripheral. The implicit prototype for this intrinsic is:


void __nop(void)

One NOP instruction is generated for each __nop() in the source. The compiler does not optimize-away the NOP instructions, except for normal unreachable-code elimination. __nop() also acts as a barrier for instruction scheduling in the compiler, that is instructions are not moved from one side of the NOP to the other as a result of optimization.

Note

You can use the __schedule_barrier() intrinsic to insert a scheduling barrier without generating a NOP instruction. See Optimization barrier intrinsics for more information.

For example:


volatile int *hw_reg1;
volatile int *hw_reg2;
int update(int input)
{
    /* update the peripheral */
    *hw_reg1 = input;
    /* allow peripheral time to update its status */
    __nop();
    /* read new status */
    return *hw_reg2;
}

Intrinsics that modify the CPSR

These functions enable you to control IRQ and FIQ interrupts (see Enabling and disabling interrupts).

The prototypes for these intrinsics are:


void __disable_irq(void);
void __enable_irq(void);
void __disable_fiq(void);
void __enable_fiq(void);

__{dis,en}able_{ir,fi}q can only be executed in privileged modes, that is, in non-user modes. In User mode these instructions do not change the interrupt flags in the CPSR.

Architectures

These intrinsics are available for all processor architectures in both ARM and Thumb state:

  • If you are compiling for processors that support ARMv6 (or later), a CPS instruction is generated inline for these functions, for example:

    
        CPSID  i
    
  • If you are compiling for processors that support ARMv4 or ARMv5 in ARM state, the compiler inlines a sequence of MRS and MSR instructions, for example:

    
        MRS  r0, CPSR
        ORR  r0, r0, #0x80
        MSR  CPSR_c, r0
    
  • If you are compiling for processors that support ARMv4 or ARMv5 in Thumb state, the compiler calls a helper function, for example:

    
        BL    __ARM_disable_irq
    

For more information on these instructions, see RealView Developer Kit v2.2 Assembler Guide.

Restrictions

You cannot use these functions to change any other CPSR bits including the mode, state, and imprecise data abort setting. This means that the intrinsics can be used only if the processor is already in a privileged mode, because the control bits of the CPSR and SPSR cannot be changed in User mode.

Optimization barrier intrinsics

The ARM compiler can perform a range of optimizations, including re-ordering instructions and merging some operations. In some cases, such as system level programming where memory is being accessed concurrently by multiple processes, it might be necessary to disable instruction re-ordering and force memory to be updated.

The following optimization barrier intrinsics do not generate code, however they can result in slightly increased code size and additional memory accesses:


void __schedule_barrier(void);
void __force_stored(void);
void __memory_changed(void):

Note

On some systems the memory barrier intriniscs might not be sufficient to ensure memory consistency. For example, the __memory_changed() intrinsic forces values held in registers to be written out to memory. However, if the destination for the data is held in a bufferable region it might wait in a write buffer. In this case you might also have to write to CP15 to drain the write buffer. Refer to the Technical Reference Manual for your ARM core for more information.

void __schedule_barrier(void)

A scheduling barrier creates a sequence point where operations before and operations after the sequence point are not merged by the compiler. A scheduling barrier does not cause memory to be updated. If variables are held in registers they are updated in place, and not written out. This intrinsic is similar to the __nop() intrinsic, except that no NOP instruction is generated.

void __force_stores(void)

A force stores barrier causes all variables that are visible outside the current function, such as variables that have pointers to them passed into or out of the function, to be written back to memory if they have been changed. The __force_stores() intrinsic also acts as a scheduling barrier.

void __memory_changed(void)

A memory changed barrier causes all variables that are visible outside the current function, such as variables that have pointers to them passed into or out of the function, to be written back to memory if they have been changed, and then to be read back from memory. The __memory_changed() intrinsic also acts as a scheduling barrier.

Copyright © 2005 ARM Limited. All rights reserved.ARM DUI 0282B
Non-Confidential