The Hi registers r8 to r12 in Cortex-m0 provide an easy way to extend the number of usable registers in the processor beyond the core r0-r7 registers. These are 16-bit alias registers that allow access to the upper 16 bits of the 32-bit r8-r12 registers. Using them correctly can help optimize code size and performance.
What are the Hi registers?
The Cortex-m0 contains 16 general purpose 32-bit registers named r0-r15. However, only the lower 8 registers r0-r7 are available for general use by software. The upper registers r8-r12 have a special purpose – they map to peripheral registers and interrupts. To allow software to utilize the full 32-bit registers while retaining their special functions, the processor implements alias 16-bit Hi registers for r8-r12.
These Hi registers can access the upper 16 bits of their corresponding 32-bit registers independently. For example, writing to r8_hi will set the upper 16 bits of r8 without affecting the lower 16 bits. This provides 12 extra 16-bit registers for the software to use.
How to access the Hi registers
The Hi registers can be accessed using the standard register addressing modes in ARM assembly: mov r0, r8_hi ; Load upper 16 bits of r8 into r0 str r1, [r2, r9_hi] ; Store r1 to address in r2 + upper 16 bits of r9 add r3, r3, r10_hi ; Add upper 16 bits of r10 to r3
When using Hi registers in C code, they need to be accessed using special macros defined in cmsis_compiler.h: uint16_t val; val = __get_APSR_HI(); // Read Hi register for APSR __set_PRIMASK_HI(0x1); // Set upper 16 bits of PRIMASK
Benefits of using Hi registers
The main benefits of using Hi registers are:
- Increased number of usable registers – Software has access to 12 additional 16-bit registers for data storage and operations.
- Code size reduction – 16-bit instructions like ADD and MOV take less space than 32-bit versions. Using Hi registers allows more code to use 16-bit encoding.
- Performance boost – 16-bit instructions execute faster than 32-bit ones. Hi register operations can improve speed in register-heavy code.
- Atomic bit manipulation – The Hi registers allow atomic read-modify-write of the upper bits in a 32-bit register. This is useful for setting status flags.
Limitations of Hi registers
While useful, the Hi registers also come with some limitations developers should keep in mind:
- Unavailable for r13-r15 – There are no Hi register aliases for the stack pointer, link register or PC.
- Only 16-bit access – Data larger than 16-bits requires multiple instructions to load/store. This may impact performance.
- No hardware interlocks – Simultaneous writes to Hi and Lo portions of a register can cause race conditions. Software must manage access to avoid errors.
- Special syntax in C – Hi registers require macros rather than standard syntax in C code. This may reduce code clarity.
Typical use cases
Here are some typical use cases where Hi registers are useful in Cortex-m0 code:
Atomic bit manipulation
// Atomically set bit #3 in GPIOA_MODER __set_GPIOA_MODER_HI(0x8);
Setting status flags often requires atomically updating a few bits in a control register while leaving other bits unchanged. Hi registers provide atomic access to the upper 16 bits for this.
Memory address extension
// Load word from address 0x1200 + value in r1 ldr r2, [r1, r8_hi] // r8_hi = 0x12
With only 16-bit registers, the Cortex-m0 has a limited direct address range. Hi registers can extend this by storing the upper address bits.
Storing constant values
// Load 5 into r0 mov r0, r8_hi // r8_hi previously initialized to 5
The Hi registers provide additional locations to store constants and flags needed by the code. This avoids consuming the core r0-r7 registers.
Temporarily saving registers
// Save r4 before function call mov r8_hi, r4 // Restore r4 after mov r4, r8_hi
When making function calls, the Hi registers provide temporary storage for saving registers that may get modified by the called function.
Tips for effective usage
To gain maximum benefit from the Hi registers, developers should keep these tips in mind:
- Reserve 1 or 2 Hi registers for temporary usage within functions. Do not rely on their values persisting across calls.
- Use Hi registers to extend addresses and store constants, to reduce pressure on core registers r0-r7.
- Prefer 16-bit operations on Hi registers to reduce code size. Minimize 32-bit operations.
- Manage Hi and Lo portions of registers separately in code. Do not assume writing one will not affect the other.
- When writing C code, encapsulate Hi register access in readable functions or macros.
The Cortex-m0 Hi registers provide a simple way to extend the usable registers in the processor, allowing for smaller and faster code. Using them effectively requires an understanding of their capabilities and limitations. Following best practices like reserving specific Hi registers, utilizing 16-bit operations, and managing Hi/Lo access can help developers optimize their Cortex-m0 code.