Instructions
3 address instruction format
- OP: operation
- Rd: destination register
- Rn, Rm: operands
Summary
Data Processing
Memory Access
PC Relative Load
Putting Address in Register
Branch
Data Processing Instructions
Format: <op>{cond}{S} Rd, Rn, Op2
op: operation mnemoniccond?: ARM V7 Assembly#ConditionsS?: should set flags in PSRRd: dest. registerRn: Operand 1 (reg.)Op2: Operand 2 (reg. or immediate data)
If we try -1 + -1:
with a carry bit
C:trueZ:falseV:falseN:true
ADDS R2, R0, #1
the S flag is used to "set" PSR flags
reg[2] <- reg[0] + 1, PSR <- N, Z, V, C
ADDEQ R5, R3, R4
if (Z == 1) reg[5] <- reg[3] + reg[4]
Arithmetic Operations
Run on the ALU
| Operation | Notes |
|---|---|
| ADD | |
| ADC | Add with carry (for 64 bit arithmetic) |
| SUB | |
| SBC | Subtract with carry |
| RSB | Reverse subtract (i.e Op2 - Op1) |
| DIVS/DIVU | Divide signed/unsigned |
| MUL |
Logical Operators
| Operation | Notes |
|---|---|
| AND | Bitwise AND |
| ORR | |
| EOR | Bitwise XOR |
| BIC | Bitwise clear: Rn * Op2' (bitwise complement of Op2) |
| ORN | Or-not: Rn + Op2' |
There is no NOT operator. Instead, use EOR against -1.
Flexible Operands
Flexible operands can either be:
- A constant (an 8-bit value) shifted 0-31 bits, which is immediate data encoded in the machine instruction
- e.g
ADD R2, R0, #1
- e.g
- A register value shifted 0-31 bits
| Operation | Meaning | Notes |
|---|---|---|
| LSL | Logical shift left | |
| LSR | Logical shift right | |
| ASR | Arithmetic shift right | Copies leftmost bit |
| ROR | Rotate right |
Data Movement
Memory Access Instructions
Access [[Memory]] on [[The Stack]]
Format: <op>{size}{cond} Rd, <address>
op: operation mnemonicsize?: size to load/store, defaults to word (4 bytes)BbyteHhalf word (2B)SBsigned byteSHsigned halfword
cond?: [[ARM V7 Assembly#Conditions]]Rd: dest. registeraddress: see below
| Operation | Full Name | Description |
|---|---|---|
| LDR | Load register | Rd <- mem[<address>] |
| STR | Store register | Rd -> mem[<address>] |
`R0: [0000 0100]`
LDR R1, [R0]
reg[1] <- mem[reg[0]]
R1: [1234 ABCD]
LDR R2, [R0, #4]
reg[2] <- mem[reg[0] + 4]
R2: [AAAA 5555]
LDRSB R3, [R0]
Load signed byte
R3: [FFFF FFCD]
LDR R1, [R0, -R2]
reg[1] <- mem[reg[0] - reg[2]]
LDR R1, [R0, R2, LSL #2]
reg[1] <- mem[reg[0] + (reg[2] << 2)]
Pre and Post-Indexed Addressing
Indexed addressing allows us to auto-increment the value of a register by some offset before or after using it. Think of it like ++i vs i++.
PC-Relative Load
See program counter, PC-relative addressing
Format: LDR{size}{cond} Rd, label
label: name for a line of code
LDR R1, SUM
reg[1] <- mem[&SUM]
where SUM is some label to some line in the code
We can write the pseudo-instruction:
LDR R1, =SUM
to store the address of the label SUM rather than the value stored at SUM, which would make it almost equivalent to the ADR instruction.
Putting Address in a Register
See program counter, PC-relative addressing
Format: ADR{cond} Rd, label
label: label of some line of code
ADR, R2, SUM
reg[2] <- &SUM
Load and Store Multiple
This requires knowledge of [[The Stack]]. More details will be available there.
Format: <op>{cond}{address-mode} Rn{!}, reg-list{^}
op: operation mnemoniccond?: [[ARM V7 Assembly#Conditions]]address-mode: [[The Stack#Full vs Empty, Ascending vs Descending Stack]]FDfull descendingFAfull ascendingEDempty descendingEAempty ascending
Rnbase register for the load operation (e.g stack pointer for loading)!specifies base register write back (i.e base register gets updated after the transfer, by one word for each register in the register list)reg-listcomma separated list of register names and ranges enclosed in braces
| Operation | Full Name | Alias |
|---|---|---|
LDM |
Load multiple | PUSH |
STM |
Store multiple | POP |
STMFD r13!, {r0-r5, LR} ; Push r0-r5 and link register onto stack
LDMFD r13!, {r0-r5, PC} ; Pop r0-r5 and the link register into the program counter from stack
Branch Instructions
Format: B{cond} label
label: label of some line of code
Compare Instructions
Compares two operands and updates the PSR flags (N, Z, C, V). Operands remain unchanged.
Format: <op>{cond} Rn, Op2
| Operation | Name | Description |
|---|---|---|
CMP |
Compare | reg[n] - op2 |
CMN |
Compare negative | reg[n] + op2 |
TST |
Test | |
TEQ |
Test equal |
TST checks if any set bits in op2 are also set in reg[n], e.g reg[n] = 1111 1111 and op2 = 0101 1010 would be true. TEQ checks for an exact match.
Compare and Branch
Format: <op> Rn, label
| Operation | Meaning |
|---|---|
CBZ |
Branch to label if reg[n] == 0 |
CBNZ |
Branch to label if reg[n] != 0 |
- Can only branch forwards
- Does not affect PSR flags