T16: the 16-bit encodings
Bits 15:11 of the halfword choose the group. Most data-processing instructions here set the flags unless they are inside an IT block, where they do not: the decoder writes adds, movs, lsls outside a block and add, mov, lsl (with the condition) inside.
| Bits 15:11 | Group | Instructions |
|---|---|---|
| 00000, 00001, 00010 | Shift by immediate | lsls Rd, Rm, #imm5, lsrs, asrs (a shift of 0 is movs Rd, Rm for lsl; 32 for lsr and asr) |
| 00011 | Add, subtract | adds Rd, Rn, Rm, subs, adds Rd, Rn, #imm3, subs |
| 00100 to 00111 | Move, compare, add, subtract with an 8-bit immediate | movs Rd, #imm8, cmp, adds Rd, #imm8, subs |
| 01000 0 | Data processing (register) | Bits 9:6: and, eor, lsl, lsr, asr, adc, sbc, ror, tst, rsb (rsbs Rd, Rm, #0), cmp, cmn, orr, mul (muls Rd, Rm, Rd), bic, mvn |
| 01000 1 | Special data and branch exchange | add Rdn, Rm and mov Rd, Rm and cmp with any of r0 to r15 (a write to r15 is a branch), bx Rm, blx Rm |
| 01001 | Load literal | ldr Rd, [pc, #imm8 × 4] (the PC is rounded down to a multiple of 4) |
| 0101 | Load and store, register offset | bits 11:9: str, strh, strb, ldrsb, ldr, ldrh, ldrb, ldrsh: Rt, [Rn, Rm] |
| 011 B L | Load and store word and byte, immediate | str/ldr Rt, [Rn, #imm5 × 4]; strb/ldrb with #imm5 |
| 1000 L | Load and store halfword, immediate | strh/ldrh Rt, [Rn, #imm5 × 2] |
| 1001 L | Load and store, stack-relative | str/ldr Rt, [sp, #imm8 × 4] |
| 10100, 10101 | Address | adr Rd, label (add Rd, pc, #imm), add Rd, sp, #imm8 × 4 |
| 1011 | Miscellaneous | See the next table |
| 1100 L | Load and store multiple | stm Rn!, {list}, ldm Rn{!}, {list} (no writeback when Rn is in the load list) |
| 1101 | Conditional branch, udf, svc | b<cond> label (cond = bits 11:8 except 1110 and 1111, offset × 2 + 4), udf #imm8 (1110), svc #imm8 (1111) |
| 11100 | Unconditional branch | b label (11-bit offset × 2) |
| 11101, 11110, 11111 | First half of a T32 instruction | See below |
| Bits 15:8 of group 1011 | Instruction |
|---|---|
| 10110000 | add sp, #imm7 × 4 (bit 7 set: sub sp, #imm7 × 4) |
| 1011 x0x1 (bits 11, 9) | cbz Rn, label, cbnz: offset i:imm5 × 2 forward only (ARMv6-M no, ARMv7 and ARMv8-M yes) |
| 10110010 | sxth, sxtb, uxth, uxtb: Rd, Rm (bits 7:6) |
| 1011 010x, 1011 110x | push {list} (bit 8 adds lr), pop {list} (bit 8 adds pc: a return) |
| 10110110 0110 x aif | cpsie, cpsid with a, i, f (bit 4 chooses id); ARMv6 and M profile (i and f) |
| 10110110 0x01 0 e 000, 10110110 0101 e 000 | setpan (ARMv8.1, bit 3), setend (bit 3 set: be) |
| 10111010 | rev, rev16, revsh, and hlt #imm6 (bits 7:6 = 10, ARMv8) |
| 10111110 | bkpt #imm8 |
| 10111111 | Hints and IT: bits 3:0 = 0000: nop (0), yield (1), wfe (2), wfi (3), sev (4), sevl (5), else hint #n; bits 3:0 ≠ 0000: it |
IT blocks
it<x><y><z> cond (0xBF00 | firstcond << 4 | mask) makes the next one to four instructions conditional. firstcond is the condition of the first instruction. The mask has a 1 as terminator: its bits above the lowest set bit say, for the second, third and fourth instruction, whether it runs on the same condition (t, then) or the opposite (e, else); the opposite of a condition is the same code with bit 0 inverted. So 0xBF08 is it eq (one instruction), 0xBF04 is itt eq, 0xBF0C is ite eq, and 0xBF01 is itttt eq.
How the decoder tracks it. It keeps the architecture’s eight-bit ITSTATE (firstcond in bits 7:4, the mask in 3:0). Each instruction decoded under a non-zero mask gets its condition as a mnemonic suffix and no S suffix on the 16-bit data-processing instructions; afterwards the state moves on (if ITSTATE[2:0] is zero the block ends, else bits 4:0 shift left by one). In a listing that decodes at every halfword, the state at an offset is found by looking back up to eight bytes for an IT instruction whose block runs exactly to this offset; so a block is recognised wherever the view starts, and an instruction in the second half of a 32-bit one is read as it would be if reached from the IT in front.
Inside the block: a conditional branch (b<cond> with its own condition) is UNPREDICTABLE except as the last instruction; it itself, and 16-bit movs Rd, Rm (lsl #0), are UNPREDICTABLE; bx, blx, b, pop {…, pc} and loads into the PC may only be the last instruction. ARMv8 deprecates IT blocks that hold more than one instruction or instructions other than a short list. The decoder flags the first three and does not flag the ARMv8 deprecation.
T32: the 32-bit encodings
With bits 12:11 of the first halfword (01 for 11101, 10 for 11110, 11 for 11111) and bits 10:4 (op2) and bit 15 of the second halfword, the groups are:
| Bits 12:11 | Bits 10:4 | Group |
|---|---|---|
| 01 | 00xx0xx | Load and store multiple (ldm, stm, push, pop, ldmdb, stmdb), srs, rfe |
| 01 | 00xx1xx | Load and store dual (ldrd, strd), exclusive (ldrex, strex and the b, h, d forms), load-acquire, store-release, table branch (tbb, tbh) |
| 01 | 01xxxxx | Data processing (shifted register): and, bic, orr, orn, eor, pkhbt, pkhtb, add, adc, sbc, sub, rsb and tst, teq, cmn, cmp, mov, mvn, shifts and rrx |
| 01 | 1xxxxxx | Coprocessor, VFP, Advanced SIMD |
| 10 | x0xxxxx, bit 15 = 0 | Data processing (modified immediate), with the immediate i:imm3:imm8 expanded by the Thumb rule (a byte, byte in alternate bytes, byte replicated, or a rotated 8-bit value with the top bit set) |
| 10 | x1xxxxx, bit 15 = 0 | Data processing (plain binary immediate): addw, subw, adr, movw, movt, ssat, usat, sbfx, ubfx, bfi, bfc |
| 10 | bit 15 = 1 | Branches and miscellaneous control: b<cond>.w, b.w, bl, blx, msr, mrs, hints, cps, barriers, bxj, eret/subs pc, lr, hvc, smc, udf.w |
| 11 | 000xxx0 | Store single data item (str, strb, strh and the T forms) |
| 11 | 00xx001, 00xx011, 00xx101 | Load byte, halfword, word, signed forms, and the preloads pld, pldw, pli |
| 11 | 010xxxx | Data processing (register): shifts by register, extends (sxtab, uxth …), parallel add and subtract, qadd, rev, rbit, clz, sel, crc32 |
| 11 | 0110xxx | Multiply, multiply-accumulate and absolute difference (mul, mla, mls, smul, smla, smuad, smlad, smmul, usad8 …) |
| 11 | 0111xxx | Long multiply and divide (smull, umull, smlal, umlal, umaal, smlald, sdiv, udiv) |
| 11 | 1xxxxxx | Coprocessor, VFP, Advanced SIMD |
The decoder writes the .w suffix as LLVM does: on instructions that also have a 16-bit encoding (add.w, mov.w, ldr.w, stm.w, b.w, nop.w), but not on those that have none (addw, movw, ldrd, sdiv, bfi, ldr r0, [r1, #-4]!).
A bl or blx in ARMv4T to ARMv6 is the same pair of halfwords with the J bits taken as 1.
T32 data processing
Shifted register: bits 8:5 of the first halfword select the operation as in A32 (0000 and, 0001 bic, 0010 orr or mov, 0011 orn or mvn, 0100 eor or teq, 0110 pkhbt and pkhtb, 1000 add or cmn, 1010 adc, 1011 sbc, 1101 sub or cmp, 1110 rsb); S is bit 4; the test instructions are the forms with Rd = 1111 and S = 1. The shift is in the second halfword (imm3 and imm2, type in bits 5:4). Modified immediate and plain binary immediate as in the table above; adr is addw or subw with Rn = pc.
T32 multiply
mul and mla (1111 1011 0000 Rn | Ra Rd 0000 Rm), mls (0001), smull, umull, smlal, umlal (1111 1011 1000 …), umaal (1111 1011 1110 … 0110), sdiv (1111 1011 1001 Rn | 1111 Rd 1111 Rm), udiv (1111 1011 1011 …). Divide needs ARMv7-M or ARMv7E-M or ARMv8, or the ARMv7-A virtualisation extensions.
T32 DSP and multiply variants
smulbb family (1111 1011 0001 …), smuad and smlad (0010), smulwb (0011), smusd and smlsd (0100), smmul and smmla (0101), smmls (0110), usad8 and usada8 (0111), smlalbb and smlald and smlsld; qadd, qsub, qdadd, qdsub (1111 1010 1000 Rn | 1111 Rd 10 op Rm). They need the DSP extension on the M profile (ARMv7E-M, ARMv8-M mainline with DSP).
T32 media instructions
Parallel add and subtract (1111 1010 1 op Rn | 1111 Rd 0 prefix Rm; the prefix in bits 6:4 of the second halfword is s 000, q 001, sh 010, u 100, uq 101, uh 110; the operation in bits 6:4 of the first is add8 000, add16 001, asx 010, sub8 100, sub16 101, sax 110), the extends sxth, uxtb16, uxtab and the rest (1111 1010 0 op Rn | 1111 Rd 1 rot Rm), rev, rev16, rbit, revsh, clz (the two copies of Rm, in bits 19:16 of the first halfword and 3:0 of the second, must be equal), sel, pkhbt, ssat, usat, ssat16, usat16, sbfx, ubfx, bfi, bfc, and crc32b/h/w, crc32cb/ch/cw (1111 1010 110 C Rn | 1111 Rd 10 sz Rm).
T32 load and store
Word, halfword and byte: first halfword 1111 1000 U S size L Rn (S is the sign bit of ldrsb and ldrsh; size 00 byte, 01 halfword, 10 word). Bit 7 of the first halfword set: a 12-bit positive offset (ldr.w Rt, [Rn, #imm12]). Otherwise the second halfword has bit 11 clear: register offset with lsl #0 to 3 (ldr.w Rt, [Rn, Rm, lsl #2]); or bit 11 set and P U W in bits 10:8: an 8-bit offset, pre-indexed, post-indexed or negative offset (ldr r0, [r1, #-4]!), or PUW = 110 the unprivileged ldrt, strt. Rn = pc is a literal load (ldr.w Rt, [pc, #±imm12]). With Rt = pc a byte or halfword load is a preload hint: pld (byte), pldw (halfword, unsigned), pli (signed byte); the other combinations are unallocated hints and shown as nop. ldrd and strd take an offset of imm8 × 4 with P, U and W in bits 8, 7, 5.
T32 load and store multiple
1110 100 op 0 W L Rn: op 01 is increment-after (ldm.w, stm.w; pop.w is ldm sp!), op 10 is decrement-before (ldmdb, stmdb; push.w is stmdb sp!), op 00 is srsdb (L = 0) and rfedb (L = 1), op 11 srsia and rfeia. The register list is the whole of the second halfword: SP in a list is UNPREDICTABLE, PC only in a load and not with LR.
T32 exclusive, acquire and release
strex Rd, Rt, [Rn, #imm8 × 4] (1110 1000 0100) and ldrex (0101); with bit 7 of the first halfword set: ldrexb, ldrexh, ldrexd, strexb, strexh, strexd (second halfword bits 7:4 = 0100, 0101, 0111), tbb and tbh (bits 7:4 = 0000, 0001), and the ARMv8 lda, ldab, ldah, stl, stlb, stlh (1000 to 1010), ldaex, stlex and their b, h, d forms (1100 to 1111).
T32 branches
b<cond>.w (1111 0 S cond imm6 | 10 J1 0 J2 imm11, 21-bit offset), b.w (1111 0 S imm10 | 10 J1 1 J2 imm11, 25-bit), bl (… 11 J1 1 J2 …), blx (… 11 J1 0 J2 …, ARM state, not in the M profile). I1 = NOT(J1 XOR S), I2 = NOT(J2 XOR S); the target is address + 4 + offset, rounded down to a multiple of 4 first for blx. udf.w #imm16 (1111 0111 1111 imm4 | 1010 imm12), hvc (1111 0111 1110 … | 1000 …), smc (1111 0111 1111 imm4 | 1000 0000 0000 0000), cbz and cbnz are 16-bit.
T32 status register
msr (1111 0011 100R Rn | 1000 mask 00 SYSm) and mrs (1111 0011 111R 1111 | 1000 Rd SYSm). On the A profile the fields are written as in A32; on the M profile the special register is named by SYSm: 0 apsr (iapsr 1, eapsr 2, xpsr 3), 5 ipsr, 6 epsr, 7 iepsr, 8 msp, 9 psp, 10 msplim, 11 psplim, 16 primask, 17 basepri, 18 basepri_max, 19 faultmask, 20 control, and the ARMv8-M non-secure aliases. cpsie.w and cpsid.w (1111 0011 1010 1111 | 1000 0 imod M AIF mode), bxj, subs pc, lr, #imm8 (eret for imm8 = 0), setend and setpan are T16.
T32 hints and barriers
1111 0011 1010 1111 | 1000 0000 hint: nop.w, yield.w, wfe.w, wfi.w, sev.w, sevl.w, dbg #n, csdb, esb; barriers: 1111 0011 1011 1111 | 1000 1111 op option: clrex (0010), dsb (0100), dmb (0101), isb (0110), sb (0111). The options are written as in A32.
T32 coprocessor instructions
The same layout as A32 with the first halfword in the high half of the word and cond 1110 (1111 for the ‘2’ forms): mcr, mrc, cdp, ldc, stc, mcrr, mrrc (1110 1110, 1110 110x, 1110 1100 010x). Coprocessors 10 and 11 are VFP; the ARMv8-A restrictions of the A32 page apply.
The M profile
ARMv6-M has the T16 instructions except cbz, it, setend and the ARMv6 extends it does have (sxtb …, rev), plus bl, msr, mrs, dmb, dsb, isb and udf.w from T32. ARMv7-M adds all the T32 integer instructions except those of the DSP extension; ARMv7E-M adds the DSP instructions; ARMv8-M baseline adds divide, cbz, movw/movt, load-acquire and store-release; ARMv8-M mainline is ARMv7-M plus those, with TrustZone (sg, bxns, blxns, tt: not decoded, see the overview). The decoder shows an instruction of a later level as undefined for an earlier one; it does not model optional extensions that a particular core lacks.