The examples use GNU assembler syntax for AArch64. A line comment starts with //. The semicolon separates statements; this book places each instruction on its own line.
ADD X0, X1, X2 // X0 = X1 + X2
| Term | Meaning |
|---|---|
| Armv8-A | An architecture version for the application profile. Implemented features depend on the processor. |
| AArch64 | The 64-bit execution state, using the A64 instruction set. |
| A64 | Fixed-width 32-bit instruction encodings; instructions can operate on 32-bit or 64-bit data. |
| AArch32 | The 32-bit execution state, using A32 or T32 where supported. |
| A32 | The instruction set traditionally called ARM, with 32-bit instruction encodings. |
| T32 | The Thumb instruction set, containing both 16-bit and 32-bit encodings. |
| Cortex-A76 | The CPU core used in Raspberry Pi 5. |
Cortex-M processors implementing Armv7-M execute Thumb instructions, not A32 instructions. Different Thumb encoding widths can appear in the same instruction stream. A32 and T32 support must not be inferred solely from a processor being described as an Arm processor.
The following encoding comparison is supplementary material. The remaining programming examples use A64.
A64
The encoding in figure 1 represents the register-copy form of MOV, an alias of ORR with the zero register as its first source. The sf bit selects a 32-bit or 64-bit operand width. It changes a bit in the instruction encoding, while the instruction itself remains 32 bits long.
The Rm and Rd fields select the source and destination. A five-bit register field has 32 possible encodings, but AArch64 has 31 general-purpose registers. In this form, encoding 31 selects the zero register. Fields fixed by this MOV alias, including N, must retain their specified values; they are not ignored or arbitrary.
A32
Figure 2 shows the same instruction, but the register address is smaller than in the A64 instruction. The bitfields' Rd' and 'Rm' are 4-bit wide, so only 16 CPU registers can be addressed using this instruction in A32.
Other bitfields, like 'cond', are also used for conditional instruction execution. The 'S' bit identifies whether the status register must be updated. The 'stype' bitfield is used for the type of shift to be applied to the second source register, and finally, the 'imm5' bitfield is used to identify the shift amount 0 to 31.
| 'stype' bit-field value | Shift type | Meaning |
|---|---|---|
| 0b00 | LSL | Logical Shift Left |
| 0b01 | LSR | Logical Shift Right |
| 0b10 | ASR | Arithmetic Shift Right |
| 0b11 | ROR | ROtate Right |
Shifts and rotations are illustrated in figures 3, 4, 5, 6 and 7. A left shift by k positions multiplies an unsigned value by 2 to the power k and keeps only the low w bits, where w is the register width. Logical right shift divides an unsigned value by that power, discarding the remainder. Arithmetic right shift preserves the sign and rounds a negative value towards negative infinity; this differs from signed division, which rounds towards zero. A rotate moves the shifted-out bits back into the opposite end of the register.
T32
The Thumb instructions have multiple machine codes for this one operation.
T1 THUMB instruction 'D' bit and 'Rd' fields together identify the destination register (figure 8). The source and destination registers can now be addressed with only 4 bits, so only 16 general-purpose registers are accessible. Fewer registers are available in the following machine code. Figures 9 and 10 present T2 and T3 THUMB instructions, respectively.
The 'OP' bitfield specifies the shift type, and imm5 specifies the amount. The result 'Rd' will be shifted by 'imm5' bits from the 'Rm' register. Notice that only three bits are used to address the general-purpose registers – only eight registers are accessible.
The T3 encoding shown in figure 10 is 32 bits wide. Its four-bit register fields identify registers in the AArch32 register set. The imm3 and imm2 fields together encode the shift amount. This instruction provides more shift operations than the previous one, but instead of a single 'imm5' field specifying the shift amount, the shift amount is split into two fields: 'imm3' and 'imm2'. Both parts are combined for the same purpose: to determine the amount of the shift.
Thumb instructions with different encoding widths can coexist in one program. The assembler chooses a supported encoding according to the instruction and its operands. The distinction between A32, T32 and A64 concerns execution states and instruction-set design, not a requirement to use one encoding width throughout a Thumb program. The examples that follow use A64 and registers X0–X30 or their W0–W30 views.