Programmers Model
Registers R0-R15, xPSR.
The programmer's model of a processor defines exactly which registers are visible to software and how they behave during normal execution, exception handling, and privilege transitions. For ARM Cortex-M, this model is the foundational knowledge required before writing a single line of assembly, configuring an RTOS, or understanding how interrupt context switching works.
Core Concept Explanation
ARM Cortex-M has 16 general-purpose registers numbered R0 through R15, all of which are 32 bits wide. Registers R0 to R12 are general-purpose but have defined roles in the ARM Procedure Call Standard (AAPCS). R0 to R3 are used to pass the first four function arguments and hold return values. Registers R4 to R11 are callee-saved, meaning a function that uses them must preserve their original values. R12 serves as an intra-procedure call scratch register used by linker veneers.
Register R13 is the Stack Pointer (SP). The Cortex-M has two physically separate stack pointers: the Main Stack Pointer (MSP) and the Process Stack Pointer (PSP). Only one is active at a time, selected by bit 1 of the CONTROL register. MSP is used by exception handlers and by the main thread when running without an RTOS. PSP is used by RTOS tasks so that the task's stack is separate from the exception handler stack.
Register R14 is the Link Register (LR), which automatically receives the return address when a BL (Branch with Link) instruction is executed. When an exception occurs, LR is loaded with a special EXC_RETURN value that encodes which stack pointer to restore and whether to return to Thread or Handler mode. Register R15 is the Program Counter (PC) and always contains the address of the next instruction to be fetched. Writing to PC causes a branch, which is how many jump and return operations are implemented.
The xPSR Status Register
The xPSR (Program Status Register) is a 32-bit combined register that is internally split into three overlapping views: APSR, IPSR, and EPSR. The APSR (Application PSR) holds the four condition flags: N (Negative), Z (Zero), C (Carry), and V (Overflow). These flags are updated by arithmetic and logical instructions and are tested by conditional execution suffixes in Thumb-2.
The IPSR (Interrupt PSR) holds the number of the currently executing exception. A value of 0 means the processor is in Thread mode (no exception). Values 1 to 15 represent system exceptions (NMI, HardFault, SVC, etc.) and values 16 and above represent external peripheral interrupts. The EPSR (Execution PSR) holds the T bit, which must always be 1 on Cortex-M because the processor only supports Thumb-2 state. If T becomes 0, the processor generates a HardFault immediately.
Special Registers and Privilege Levels
The Cortex-M supports two privilege levels: Privileged and Unprivileged. Privileged mode has access to all registers and system configuration. Unprivileged mode cannot access the system control block, NVIC, or SysTick directly. The CONTROL register selects which mode the Thread mode executes in and which stack pointer is active. This two-level privilege model is fundamental to building secure RTOS-based systems where application tasks cannot corrupt the kernel.
PRIMASK, BASEPRI, and FAULTMASK are interrupt masking registers accessible only from privileged code. PRIMASK disables all maskable interrupts when set to 1, used for short critical sections. BASEPRI masks all interrupts with a priority number greater than or equal to the programmed value, enabling fine-grained interrupt shielding. FAULTMASK additionally disables all faults except NMI and is used only in fault recovery routines.
Mathematical Expression
The N, Z, C, V flags in APSR are updated after each arithmetic instruction. For a subtraction operation A minus B implemented as A + (~B) + 1 (two's complement addition), the carry flag C indicates unsigned borrow (C = 0 means borrow occurred). The overflow flag V is set when the signed result exceeds the 32-bit signed range. A common GATE question derives the relationship: for an N-bit subtraction, borrow = NOT(C) when the ARM carries out subtraction via addition of two's complement.
Practical Understanding
In an RTOS like FreeRTOS running on Cortex-M, each task has its own stack and uses PSP. When the SysTick timer triggers a context switch, the kernel saves R4-R11 (since R0-R3, R12, LR, PC, xPSR are hardware-saved automatically on exception entry), switches PSP to point to the new task's stack, restores R4-R11 from the new task's stack, then executes BX LR using the EXC_RETURN value to return to Thread mode using PSP. Understanding this register map is the minimum knowledge required to write or debug an RTOS port.
Given:
R0 = 0x00000050 (decimal 80)
R1 = 0x00000090 (decimal 144)
Instruction: SUBS R2, R0, R1 (R2 = R0 - R1 = 80 - 144)
Why this formula applies:
SUBS updates APSR flags. Subtraction on ARM = A + (~B) + 1
Formula:
Result = R0 + NOT(R1) + 1 = 80 + (NOT 144) + 1 = 80 - 144 = -64
Substitution:
Result (unsigned) = 0x00000050 + 0xFFFFFF6F + 1 = 0xFFFFFFC0
Calculation:
R2 = 0xFFFFFFC0 (signed = -64)
N flag = 1 (MSB is 1, result is negative)
Z flag = 0 (result is not zero)
C flag = 0 (borrow occurred, since 80 < 144 unsigned)
V flag = 0 (no signed overflow, -64 is within range)
Final Answer:
R2 = 0xFFFFFFC0, N=1, Z=0, C=0, V=0. Borrow = NOT(C) = 1 confirms unsigned underflow.Exam Tip: On ARM Cortex-M, borrow from a subtraction is the logical NOT of the Carry flag (C=0 means borrow occurred). This is opposite to the convention used in x86. GATE questions on flag computation after SUB instructions frequently test this specific difference.
Mechanism: Register Usage in Function Calls
- R0-R3 hold function arguments and the return value. The caller may freely use these after a call without saving them. If a function needs more than four arguments, the extra ones are passed on the stack.
- R4-R11 are preserved across calls. The callee must save these to the stack using PUSH on entry and restore them using POP on return.
- LR holds the return address. For a leaf function that makes no further calls, it can directly BX LR. For non-leaf functions, LR must be pushed to stack and popped into PC on return.
- The T bit in EPSR must always remain 1. Branching to an address with bit 0 clear would clear T and cause an immediate HardFault exception.
- On exception entry, hardware automatically saves R0-R3, R12, LR, PC, and xPSR onto the active stack. Software must separately save R4-R11 if the ISR uses those registers.
Quick Revision
- 16 registers total, all 32-bit. R0-R12 general purpose, R13 = SP, R14 = LR, R15 = PC.
- Two stack pointers: MSP (exceptions, privileged) and PSP (RTOS tasks). CONTROL register bit 1 selects active SP.
- xPSR = APSR (N,Z,C,V,Q flags) + IPSR (exception number) + EPSR (T bit). T bit must always be 1.
- Caller-saved: R0-R3, R12. Callee-saved: R4-R11. Return value in R0.
- Hardware auto-saves R0-R3, R12, LR, PC, xPSR on exception entry. ISR only needs to save R4-R11 if used.
- Exam trap: On ARM, borrow = NOT(C). C=0 after SUBS means unsigned underflow, opposite to x86 borrow convention.
- PRIMASK=1 disables all IRQs. BASEPRI masks IRQs at or below a priority level. FAULTMASK masks all faults except NMI.
ARM Programmers Model
Test your knowledge on this topic!
Q1.Which core register serves as the Program Counter (PC) in the Cortex-M architecture?
Related Articles
Instruction Set
Thumb-2 instruction set highlights.
8 min read
Memory Map
Code, SRAM, Peripheral bit-band regions.
12 min read
Exception Handling
Entry/Exit sequences, tail-chaining.
11 min read
Embedded Systems Overview
Definition, constraints, design metrics.
9 min read
Design Life Cycle
Waterfall model, V-model.
6 min read