|ARM Technical Support Knowledge Articles|
SWP (pre-ARMv6 architectures) and
STREX (ARMv6 and later) are instructions designed to support multi-master systems. For example, a multi-master system could be a system with multiple cores and other bus masters like DMA controllers. The primary purpose of these instructions is to maintain the integrity of shared data structures during inter-master communication by preventing masters from making conflicting accesses at the same time.
SWP provides an atomic load and store operation which can be used as the basic building block for mutexes and semaphores.
ARMv6 also introduced a pair of synchronization primitives,
STREX, which allow a bus master to detect that another master has written to an address that requires exclusive access. The advantage of
STREX is that it does not prevent other transactions on the bus from executing. In contrast, a core executing
SWP takes over the bus until the instruction is completed, by asserting the
These instructions are also useful on a single master system to implement mutexes, semaphores, etc. without needing to disable interrupts. In the same way, they are also useful for multi-threaded systems.
SWP has been deprecated in ARMv7 and beyond. On a v6 or later core (ARM11 onwards) you should use the
STREX instructions instead. ARMv7 also adds byte, halfword and doubleword versions of the synchronization primitives:
Here we have a very simple spin-lock example showing
STREX in action. We check to see if an address is "locked" using the
LDREX instruction. If it isn't locked and is available to use, we then store the "locked" value to the address using the
; void lock(lock_t* pAddr)
; Is locked?
LDREX r1, [r0] ; Check if locked
CMP r1, #LOCKED ; Compare with “locked“
BEQ lock ; If LOCKED, try again
; Attempt to lock
MOV r1, #LOCKED
STREX r2, r1, [r0] ; Attempt to lock
CMP r2, #0x0 ; Check whether store completed
BNE lock ; If store failed, try again
For more information please see the ARM Architecture Reference Manual and the AMBA documentation.
The compiler will not generate either
STREX when compiling normal C or C++ source code. This is because the C and C++ language specifications do not mention these kind of operations and therefore there are no operators in the language that map to these instructions.
You can, however, use one of the following methods to access these instructions in your program:
Compiler intrinsics. For example:
STREXbased on the size of the parameter. For example:
__ldrex( (char *) ptr ) // generates LDREXB
__ldrex( (short *) ptr) // generates LDREXH
__ldrex( (int *) ptr ) // generates LDREX
__swp, __ldrex and
__strex intrinsics were introduced in RVCT 3.1. The
__strexd intrinsics were added in RVCT 4.0. The compiler reports an error if
__strexd are compiled for
--cpu targets that do not support
The embedded assembler or inline assembly. For example:
/* Embedded assembler to access the SWP instruction */
__asm atomic_swap(unsigned int read, unsigned int write, unsigned int addr)
ARM Compiler 5.06 deprecated the
__strex family of intrinsics, and also deprecated the use of the
STREX family of instructions in inline assembly code. The appropriate workaround is to use these instructions in an embedded assembler function or to use the
__sync_* family of GNU built-in functions instead for development using ARM Compiler 5.06 and later.
Article last edited on: 2016-05-27 16:22:17
Did you find this article helpful? Yes No
How can we improve this article?