Thumb-1 instructions are a 16-bit compressed instruction set that is supported by Arm Cortex-M series microcontrollers. Thumb-1 provides a balance between code density and performance compared to the 32-bit Arm instruction set. Thumb-1 instructions are used to reduce code size while maintaining much of the performance of the full Arm instruction set.
Overview of Thumb-1
Thumb-1 is a 16-bit instruction set that was introduced in Arm processors starting with the Arm7TDMI in 1995. It is intended to improve code density compared to the full 32-bit Arm instruction set. Thumb-1 instructions are 16 bits wide rather than 32 bits, allowing for smaller program code. The Cortex-M series of microcontrollers support both Arm and Thumb-1 instruction sets.
With Thumb-1, many frequently used Arm instructions are replaced by 16-bit Thumb-1 instructions. This provides improved code density while maintaining performance for common operations. Thumb-1 also has its own set of 16-bit instructions that do not correspond to Arm instructions. The processor automatically switches between Arm and Thumb-1 states when executing instructions.
Thumb-1 is supported in all Cortex-M series processors from the Cortex-M0 to M7. It provides a good balance of code size and performance for embedded applications. Typical code size reductions when using Thumb-1 range from 25-30% compared to only using the Arm instruction set.
Features of Thumb-1
The key features of the Thumb-1 instruction set are:
- 16-bit instruction length – Improves code density compared to 32-bit Arm instructions
- Supports most common Arm instructions – Maintains performance for frequent operations
- Specialized 16-bit only instructions – Provides additional performance gains
- Automated switching between Arm and Thumb states – Simplifies mixing 16-bit and 32-bit code
- Supported in all Cortex-M processors – Widely available for microcontroller applications
By using 16-bit instructions for many common operations like basic arithmetic, logical operations, and load/store, Thumb-1 provides significant code size reductions. Critical software performance is maintained by supporting the most used 32-bit Arm instructions in Thumb-1 via automatic processor state switching.
Thumb-1 Instruction Encoding
The 16-bit Thumb-1 instruction encoding is designed to provide a dense mapping to frequently used Arm instructions as well as space for specialized 16-bit instructions. Thumb-1 instructions can be categorized into the following groups:
- Core Arm instructions – 16-bit Thumb equivalents of common Arm instructions
- Load/store instructions – Special Thumb load/store instructions
- PCR/Branch instructions – Thumb specific branch and PC relative instructions
- Miscellaneous instructions – Additional specialized instructions with no Arm equivalent
The Thumb-1 encoder uses bits 12-15 to encode the instruction class. Bits 0-11 encode the actual instruction within each class. This scheme allows for 16 variants of each instruction class to be encoded in 16 bits.
For example, simple arithmetic instructions like add and subtract are encoded using bits 12-15 = 0000. Logical instructions like and, or, xor use the pattern 0001. Load/store instructions have their own range of encodings from 0100-0101. This organized structure allows Thumb instructions to be densely packed while still being easily decoded.
Interworking Between Thumb and Arm States
The Cortex-M processors support the ability to mix and match Arm and Thumb-1 instructions by automatically switching states. Some key points regarding Arm/Thumb interworking:
- The processor begins executing code in Arm or Thumb state based on a configuration option
- Branching between Arm and Thumb code is allowed via interworking branches
- Subroutines can be called from Arm code to Thumb code and vice versa
- Interworking reduces need to manually manage Arm vs Thumb regions
This interworking capability greatly simplifies using Thumb-1. Individual functions or regions of code can be written in Thumb-1 without needing to segregate Arm and Thumb code. The processor handles switching between the Arm and Thumb instruction sets automatically.
Cortex-M Branch Instructions
The Thumb-1 instruction set in Cortex-M processors contains several branch instructions to help improve flow control performance:
- B – Standard PC relative branch
- BL – Branch with link register for subroutine calls
- BX – Branch and exchange instruction set state
- BLX – Branch, link, and exchange instruction set state
The B and BL instructions allow for PC relative branching, which is useful for creating branch tables and position independent code. BL additionally stores the return address in the link register for subroutine calls.
The BX and BLX instructions perform both branching and switching between Arm/Thumb states. This allows for seamless interworking and calling subroutines between Arm and Thumb code.
Thumb-1 contains several specialized load/store instructions to improve memory access performance:
- LDR(B) – Load register with byte or word from memory
- STR(B) – Store register byte or word to memory
- LDMIA – Load multiple registers from stack
- STMIA – Store multiple registers to stack
These provide more efficient loading and storing than using LDR/STR with Arm address registers. The stack-oriented LDMIA and STMIA are especially useful for pushing/popping register contents to the stack.
Miscellaneous 16-bit Instructions
Some other useful 16-bit only Thumb instructions include:
- CBNZ/CBZ – Compare and branch if zero/nonzero
- IT – If-then conditional execution
- TBB/TBH – Table branch byte/halfword
IT allows up to 4 following instructions to be conditionally executed based on the flags. TBB/TBH performs branches using a branch table in memory, useful for switch statements.
These special purpose instructions have no direct Arm equivalent and help optimize certain code sequences.
While Thumb-1 provides improved code density, it does have some limitations compared to the Arm instruction set:
- Only 16 registers directly accessible vs 32 in Arm
- Limited operational range for offsets and immediates
- No barrel shifter support
- More instructions required for some operations
The 16-bit instruction format limits the range of constants and offsets that can be encoded. Lack of a barrel shifter means more instructions are needed for multiplier and divider operations. These limitations mean Thumb-1 code is typically slower than Arm code, but the size benefits often outweigh the performance costs for microcontrollers.
Overall, Thumb-1 provides an excellent balance of code density and performance for Cortex-M embedded applications. Key takeaways include:
- 16-bit instruction set that reduces code size 25-30% vs Arm
- Supports most common Arm instructions for performance
- Special Thumb-only instructions enhance code density
- Automatic Arm/Thumb interworking simplifies usage
- Widely supported in all Cortex-M series processors
For microcontroller applications where smaller code size is critical, Thumb-1 will generally provide the best results. Performance sensitive code regions can always be switched to Arm instructions when needed. Thumb-1 represents an evolutionary improvement over Arm that enables much better code density for embedded systems.