The ARMv7-M architecture is a 32-bit ARM processor architecture that is optimized for microcontroller applications. It includes the Thumb-2 instruction set, which is a superset of the original 16-bit Thumb instruction set. The Thumb-2 instruction set provides both high code density through 16-bit Thumb instructions and high performance through 32-bit ARM instructions. This article provides an overview of the key features of the Thumb instruction set in ARMv7-M.
Introduction to Thumb
The Thumb instruction set was introduced in ARMv4T to improve code density. Thumb instructions are 16 bits long, compared to 32 bits for ARM instructions. This provides roughly 65% better code density on average. The tradeoff is that some Thumb instructions require more instructions to accomplish the same task as a single ARM instruction. The dual 16-bit and 32-bit instruction sets allow developers to choose the best approach for their specific needs in terms of performance versus code size.
Thumb-2 Instruction Set
Thumb-2 extends the original Thumb instruction set with additional 16-bit instructions as well as 32-bit Thumb instructions. This allows Thumb-2 to achieve similar performance to the ARM instruction set while retaining the code density benefits of Thumb. Key features of Thumb-2 include:
- 16-bit and 32-bit instruction support
- Improved conditional execution support
- Hardware interworking between ARM and Thumb states
- 16 new 32-bit instructions that provide ARM equivalents for complex Thumb instruction sequences
- Access to all ARM registers from Thumb state
Thumb-2 16-bit Instructions
The Thumb-2 16-bit instruction set builds on the original Thumb instruction set with the following enhancements:
- Conditional execution – Allows if-then type conditional execution based on status flags.
- Hi-register addressing – Provides instructions that can access the 8 high registers (R8-R15).
- SIMD instructions – Adds single instruction multiple data (SIMD) instructions for improved media processing.
- Load/store dual – Provides instructions that can load/store two registers using a single instruction.
- Branch and branch with link and exchange – Improves branch instruction flexibility.
These 16-bit Thumb-2 instructions provide improved performance and functionality while maintaining the high code density advantage of Thumb. Key types of 16-bit Thumb-2 instructions include:
- Data processing
- Load/Store
- Move
- Branch
- Multiply and Divide
- Hint
- IT and IF-THEN
- Miscellaneous
Thumb-2 32-bit Instructions
The Thumb-2 extension adds 13 new 32-bit instructions that provide access to functionality that previously required multiple 16-bit Thumb instructions. This improves performance for some operations while retaining Thumb’s code density for other parts of code. The 13 instructions added are:
- ADD (register)
- SUB (register)
- ADD (immediate)
- SUB (immediate)
- MOV
- CMP
- NOP
- BKPT
- PUSH/POP
- SETEND
- CPY
- CBNZ/CBZ
These powerful 32-bit instructions allow efficient access to ARM capabilities from Thumb state. This balances high density Thumb coding with high performance ARM operations.
Interworking Between ARM and Thumb
A key feature of Thumb-2 is the ability to seamlessly interwork between ARM and Thumb states. This allows developers to write code using a mix of 16-bit and 32-bit instructions tailored for each specific purpose. Interworking works as follows:
- BX and BLX instructions switch between ARM and Thumb states
- Branches from ARM to Thumb code automatically switches state
- Return from interrupts switches back to previous state
- Compiler manages register usage between states
Interworking results in the following advantages:
- Flexible mixing of ARM and Thumb at subroutine boundaries
- Small performance critical routines can use 32-bit ARM instructions
- Main code uses high density 16-bit Thumb instructions
Overall, interworking provides a seamless experience allowing developers to get the best of both instruction sets.
ARM and Thumb Registers
The ARMv7-M architecture has 16 32-bit general purpose registers, R0-R15. In Thumb state, the low registers R0-R7 can be accessed using all Thumb instructions. The high registers R8-R15 require specific Thumb instructions that support high register addressing modes.
In ARM state, all 16 registers R0-R15 are accessible with all instructions. When switching between ARM and Thumb, the register mapping is maintained transparently.
Stack Support
For stack operations, ARM state uses the SP (R13) register directly for push/pop instructions. In Thumb state, stack operations are performed using the SP but use different syntax:
- PUSH/POP instructions in Thumb state
- LDM/STM instructions in ARM state
Despite the syntactic differences, SP maintains stack coherence when switching between ARM and Thumb states.
Conditional Execution
Most Thumb instructions permit conditional execution based on status flags. This allows if-then type conditionals without branches:
ITE EQ // If Then Else
ADDEQ R1, R2, R3 // ADD if Z set
SUBNE R1, R2, R4 // SUB if Z clear
Conditional execution avoids branches and improves performance in some scenarios. ARM instructions also support conditional execution.
IT and If-Then Instructions
The IT instruction sets up conditional execution of up to 4 subsequent instructions. The IT syntax is:
IT{x{y{z}}} cond
This allows multiple instructions to be conditionally executed without branching. The If-Then instructions are a specialized case of IT with only 2 instructions.
ITEQ ADDLE R1, R2, R3
ITTE SUBLE R4, R5, R6
IT and If-Then blocks offer flexibility for conditional execution without branches.
Load/Store Multiple
Thumb-2 provides push/pop instructions for loading/storing multiple registers to the stack. Syntax examples:
PUSH {R4,LR} // Push R4 and LR
POP {R4-R6,PC} // Pop R4-R6 and PC
This provides simple syntax for stack operations rather than multiple LDR/STR instructions.
Position Independence
The Thumb instruction set supports position independent code. Three key techniques are used:
- PC relative addressing – References are PC relative offsets
- Address lookup tables – Base addresses stored in tables
- Position independence helpers – Helper routines hide addressing
Position independent code allows Thumb applications to be loaded and execute from any memory location.
Summary
In summary, the Thumb-2 instruction set provides an optimal blend of high code density, good performance, and flexibility for microcontroller applications. Key points include:
- 16-bit Thumb and 32-bit Thumb instructions
- Thumb-2 enhances original Thumb significantly
- Interworking for mixing Thumb and ARM code
- Conditional execution without branches
- Position independence support
The Thumb-2 instruction set enables ARM Cortex-M microcontrollers to achieve both high code density and high performance.