General Reference
Size of bytes
1 byte = 8 bits
1KB = bytes = 1024 bytes
1MB = bytes = 1,048,576 bytes
1GB = bytes = 1,073,741,824 bytes
Memory sizes
Size at each address = 8 bits
Size of address (assumed) = 16 bits
Size of each register in CPU = 32 bits.
There are 16 registers in CPU (R0-R12; R13=SP; R14=LP; R15=PC; CSPR)Memory capacity in BYTES =
Number of BITS in one data transfer = number of data pins
Size of numbers
| Type | Bytes | Bits | Range |
|---|---|---|---|
| signed char | 1 | 8 | |
| unsigned char | 1 | 8 | |
| short int | 2 | 16 | |
| unsigned short int | 2 | 16 | |
| unsigned int | 4 | 32 | |
| int | 4 | 32 | |
| long int | 4 | 32 | |
| long long int | 8 | 64 | |
| float | 4 | 32 | |
| double | 8 | 64 | |
| long double | 12 | 96 |
Data types should be aligned to address that is a multiple of the data bus.
Little Endian (LSB at lowest address; assume this) vs Big Endian (MSB at highest address).
Size of instructions and its components/operands
One instruction: 32 bits / 4 bytes
Condition flags: 4 bits (Bits 28-31)
Opcode: 8 bits (Bits 20-27)
Register: 4 bits (Since there are 16 possible registers in the processor)
Immediate value: 12 bits (4 rotate right bits + 8 bit immediate value.)
Execution Cycle
Fetch-Decode-Execute PC value is 8 bytes ahead of current instruction being executed. For PC-related addressing, must have offset of 8bytes. The max offset is bytes or (#0xFC) , offset field only has 12 bits.
Instruction Set
| VisUAL ARM Instruction Set | ||
|---|---|---|
| Summary | Opcode | Syntax |
| Move | MOV | MOV{S}{cond} dest, op1 {, SHIFT op
#expression} S=1: NZC, C if shift occurs. |
| Move Negated | MVN | MVN{S}{cond} dest, op1 {, SHIFT op
#expression} Inverts op1 bitwise (1’s comp) before moving. S=1: NZC, C if shift occurs. |
| LDR Psuedo-Instruction | LDR | LDR{S}{cond} dest, =expression |
| Add | ADD | ADD{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1, updates NZCV. |
| Add with Carry | ADC | ADC{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} dest = op1 + op2 + C S=1, updates NZCV. |
| Subtract | SUB | SUB{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1, updates NZCV. |
| Subtract with Carry | SBC | SBC{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} dest = op1 - op2 - NOT(C) S=1, updates NZCV. |
| Reverse Subtract | RSB | RSB{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} dest = op1 - op2 S=1, updates NZCV. |
| Reverse Subtract with Carry | RSC | RSC{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} dest = op2 - op1 - NOT(C) S=1, updates NZCV. |
| Bitwise And | AND | AND{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1: NZC, C if shift occurs. |
| Bitwise Exclusive Or | EOR | EOR{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1: NZC, C if shift occurs. |
| Bitwise Clear | BIC | BIC{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1: NZC, C if shift occurs. |
| Bitwise Or | ORR | ORR{S}{cond} dest, op1, op2 {, SHIFT_op
#expression} S=1: NZC, C if shift occurs. |
| Logical Shift Left | LSL | LSL{S}{cond} dest, op1, op2 S=1: NZC, C gets the last bit shifted out. |
| Logical Shift Right | LSR | LSR{S}{cond} dest, op1, op2 S=1: NZC, C gets the last bit shifted out. |
| Arithmetic Shift Right | ASR | ASR{S}{cond} dest, op1, op2 MSB unchanged. If S=1, C=LSB. S=1: NZC, C gets the last bit shifted out. |
| Rotate Right | ROR | ROR{S}{cond} dest, op1, op2 LSB into MSB. If S=1, C=LSB. S=1: NZC, C gets the last bit shifted out. |
| Rotate Right and Extend | RRX | RRX{S}{cond} op1, op2 C into MSB. If S=1, C=LSB. S=1: NZC, C gets the last bit shifted out. |
| Compare | CMP | CMP{cond} op1, op2 {, SHIFT_op
#expression} Test (op1 - op2), same as SUBS without modification Always updates NZCV. |
| Compare Negated | CMN | CMN{cond} op1, op2 {, SHIFT_op
#expression} Tests (op1 + op2), same as ADDS w/o modification Always updates NZCV. |
| Test Bit(s) Set | TST | TST{cond} op1, op2 {, SHIFT_op
#expression} Bitwise AND b/w operands Always updates NZC. |
| Test Equals | TEQ | TEQ{cond} op1, op2 {, SHIFT_op
#expression} Bitwise XOR b/w operands Always updates NZC. |
| Load Register | LDR | LDR{B}{cond} dest, [source {, OFFSET}]
Offset addressing LDR{B}{cond} dest, [source, OFFSET]! Pre-indexed addressing LDR{B}{cond} dest, [source], OFFSET Post-indexed addressing |
| Store Register | STR | STR{B}{cond} source, [dest {, OFFSET}]
Offset addressing STR{B}{cond} source, [dest, OFFSET]! Pre-indexed addressing STR{B}{cond} source, [dest], OFFSET Post-indexed addressing |
| Load Multiple Registers | LDM[dir] | LDM[dir]{cond} source, {list of registers} |
| Store Multiple Registers | STM[dir] | STM[dir]{cond} dest, {list of registers} |
| Branch | B | B{cond} target |
| Branch with Link | BL | BL{cond} target |
| Stop Emulation | END | END{cond} |
Memory Access and Clock Cycles per Instruction
| Instruction Type | Memory Accesses (Data + Instr) | Total Accesses | Clock Cycles |
|---|---|---|---|
| Data Processing (Standard) | |||
| MOV, ADD, SUB, AND, ORR, etc. | 1 (Instr) + 0 (Data) | 1 | 1 |
| MOVEQ (Conditional Move) | 1 (Instr) + 0 (Data) | 1 | 1 (True or False) |
| Comparisons (CMP, CMN, TST, TEQ) | 1 (Instr) + 0 (Data) | 1 | 1 |
Data Proc. with Register Shift (e.g.
LSL Rs) |
1 (Instr) + 0 (Data) | 1 | 1 |
| Control Flow (Branches modify PC) | |||
| B (Unconditional Branch) | 1 (Instr) + 0 (Data) | 1 | 3 (Pipeline Flush) |
| BEQ / BCC (Conditional Branch) | 1 (Instr) + 0 (Data) | 1 | 1 (False) or 3 (True) |
| BL (Branch with Link) | 1 (Instr) + 0 (Data) | 1 | 3 (Pipeline Flush) |
| BX LR (Branch and Exchange) | 1 (Instr) + 0 (Data) | 1 | 3 (Pipeline Flush) |
| MOV PC, LR (Return from Branch) | 1 (Instr) + 0 (Data) | 1 | 3 (Pipeline Flush) |
Data Proc. writing to PC (e.g.
ADD PC, ...) |
1 (Instr) + 0 (Data) | 1 | 3 (Pipeline Flush) |
| Single Data Transfer | |||
| LDR / STR (Single Load/Store) | 1 (Instr) + 1 (Data) | 2 | 2 |
| LDREQ / STREQ (Conditional) | 1 (Instr) + 0 or 1 (Data) | 1 or 2 | 1 (False) or 2 (True) |
| Block Data Transfer (Stack) | |||
| LDMFD (Load Multiple, Full Desc.) | 1 (Instr) + N (Data) | ||
| STMFD (Store Multiple, Full Desc.) | 1 (Instr) + N (Data) |
Condition Codes
| Code | Suffix | Flags | Meaning |
|---|---|---|---|
| 0000 | EQ | Equal | |
| 0001 | NE | Not equal | |
| 0010 | CS or HS | Higher or same, unsigned | |
| 0011 | CC or LO | Lower, unsigned | |
| 0100 | MI | Negative | |
| 0101 | PL | Positive or zero | |
| 0110 | VS | Overflow | |
| 0111 | VC | No overflow | |
| 1000 | HI | and | Higher, unsigned |
| 1001 | LS | or | Lower or same, unsigned |
| 1010 | GE | Greater than or equal, signed | |
| 1011 | LT | Less than, signed | |
| 1100 | GT | and | Greater than, signed |
| 1101 | LE | and | Less than or equal, signed |
| 1110 | AL | Can have any value | Always. This is the default when no suffix is specified. |
| 1111 | NV | Reserved (unused) |
SUBS sets C=1 when no borrow (A - B, where A B); clears C=0 if borrow (A - B, where A B).
Condition to set the flags:
N: MSB = 1.
Z: All zero.
V: MSB of result MSB of operands, where MSB of operands are the same.
C: Bit carried out = 1.
Instruction Anatomy
Data processing instructions
XXXCCS Rd, Rs1, #immediate (rotated)XXXCCS Rd, Rs1, Rs2, {shft #}XXXCCS Rd, Rs1, Rs2, {shft Rshift}Branch instructions
B(L)CC OffsetIf L=0, then is B. If L=1, then is BL.
Offset is distance between current instruct & target addr.
Effectively acts as 26-bit offset. Branch range:
Mbytes.
Load/store instructions
LDR/STR{B}CC Rs, [Rd, offset pre or post]!LDR/STR{B}CC Rs, [Rd, offset pre or post]!(The maximum offset for register indirect with immediate value is
bytes. The sign is determined by U bit.)
(1/0): P = Pre/post; U = add/subtract; B = byte/32-bit word; W =
writeback/no wb; L = load/store;
LDM/STM{mode}CC Rs{!}, {register list}B becomes "don’t care" bit; register list bit 0 is R0, bit 15 is R15, 1=include that register.
| Bits 27–25 | Instruction Category | Meaning |
|---|---|---|
000 |
Data Processing | Register/Shift Operand () |
001 |
Data Processing | Immediate Operand () |
010 |
Load/Store Single | Register Offset |
011 |
Load/Store Single | Immediate Offset |
100 |
Load/Store Multiple | Block Data Transfer
(LDM/STM) |
101 |
Branch | Branch/Jump Instruction
(B/BL) |
| Code | Instruction | Code | Instruction |
|---|---|---|---|
| 0000 | AND | 1000 | TST |
| 0001 | EOR | 1001 | TEQ |
| 0010 | SUB | 1010 | CMP |
| 0011 | RSB | 1011 | CMN |
| 0100 | ADD | 1100 | ORR |
| 0101 | ADC | 1101 | MOV |
| 0110 | SBC | 1110 | BIC |
| 0111 | RSC | 1111 | MVN |
| Code | Shift type |
|---|---|
| 00 | LSL |
| 01 | LSR |
| 10 | ASR |
| 11 | ROR/RRX |
| PU^WL Bits | Instruction |
|---|---|
| 00011 | LDMFA (Pop) |
| 01011 | LDMFD (Pop) |
| 10010 | STMFD (Push) |
| 11010 | STMFA (Push) |
| 00010 | STMED (Push) |
| 01010 | STMEA (Push) |
| 10011 | LDMEA (Pop) |
| 11011 | LDMED (Pop) |
Flow control
IF statement: reverse the condition to reduce jump
instructions.
Condtional execution: add the condtion codes to the instruction (e.g.
MOVEQ). If using multiple of these, ensure the CSPR unchanged.
Compound AND: If first condition fail, branch out immediately.
Compound OR: If first cond pass, branch immediately.
SWITCH with narrow consecutive values, use jump table.
SWTICH with wide range of values, use forked cascade.
PRE-test loops (WHILE): Test condition at the start, branch out if
fail.
POST-test loops (DO-WHILE): Test at the end.
FOR loops are pre-test loops.
ASCII table
| Bits: / | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |||||
| 0 | 0 | 0 | 0 | 0 | NUL | DLE | SP | 0 | @ | P | ` | p |
| 0 | 0 | 0 | 1 | 1 | SOH | DC1 | ! | 1 | A | Q | a | q |
| 0 | 0 | 1 | 0 | 2 | STX | DC2 | " | 2 | B | R | b | r |
| 0 | 0 | 1 | 1 | 3 | ETX | DC3 | # | 3 | C | S | c | s |
| 0 | 1 | 0 | 0 | 4 | EOT | DC4 | $ | 4 | D | T | d | t |
| 0 | 1 | 0 | 1 | 5 | ENQ | NAK | % | 5 | E | U | e | u |
| 0 | 1 | 1 | 0 | 6 | ACK | SYN | & | 6 | F | V | f | v |
| 0 | 1 | 1 | 1 | 7 | BEL | ETB | ’ | 7 | G | W | g | w |
| 1 | 0 | 0 | 0 | 8 | BS | CAN | ( | 8 | H | X | h | x |
| 1 | 0 | 0 | 1 | 9 | HT | EM | ) | 9 | I | Y | i | y |
| 1 | 0 | 1 | 0 | 10 | LF | SUB | * | : | J | Z | j | z |
| 1 | 0 | 1 | 1 | 11 | VT | ESC | + | ; | K | [ | k | { |
| 1 | 1 | 0 | 0 | 12 | FF | FS | , | < | L | \ | l | | |
| 1 | 1 | 0 | 1 | 13 | CR | GS | - | = | M | ] | m | } |
| 1 | 1 | 1 | 0 | 14 | SO | RS | . | > | N | ^ | n | ~ |
| 1 | 1 | 1 | 1 | 15 | SI | US | / | ? | O | _ | o | DEL |
Stacks
| Type | Characteristics | Push Action (Store) | Pop Action (Load) | Access Top Item |
|---|---|---|---|---|
| FD | Full Descending Grows Down () SP points to: Data |
Pre-Decrement STR Rn, [SP, #-4]! PU^WL: 1010 |
Post-Increment LDR Rn, [SP], #4 PU^WL: 0111 |
No Offset LDR Rn, [SP] |
| ED | Empty Descending Grows Down () SP points to: Empty |
Post-Decrement STR Rn, [SP], #-4 PU^WL: 0010 |
Pre-Increment LDR Rn, [SP, #4]! PU^WL: 1111 |
Plus 4 LDR Rn, [SP, #4] |
| FA | Full Ascending Grows Up () SP points to: Data |
Pre-Increment STR Rn, [SP, #4]! PU^WL: 1110 |
Post-Decrement LDR Rn, [SP], #-4 PU^WL: 0011 |
No Offset LDR Rn, [SP] |
| EA | Empty Ascending Grows Up () SP points to: Empty |
Post-Increment STR Rn, [SP], #4 PU^WL: 0110 |
Pre-Decrement LDR Rn, [SP, #-4]! PU^WL: 1011 |
Minus 4 LDR Rn, [SP, #-4] |
Modular Programming
Branch to subroutine (both change LR and PC).
BL.MOV LR PC; B SUBROUTINE.
Return to calling program (both only change PC).
BX LR.MOV PC LR.
STMFD SP! {R6-R7, LR}: R6 at lowest memory, LR at
highest memory, i.e. SP pointing at R6.
LDMFD SP! {R6-R7, PC}: PC takes over saved LR
content.
Immediately after executing BL Sub1 located at 0x300, LR =
0x304.
Registers:
R0 – R3: Arguments (Inputs) & Return Values. Volatile / Caller-saved. (Can be safely overwritten).
R4 – R11: Local Variables. Non-volatile / Callee-saved. (MUST be preserved for transparent subroutines).
R11: Frame pointer (use negative offset)
R12 (IP): Intra-procedure scratch register. Volatile. (Can be safely overwritten).
R13 (SP): Stack Pointer. Points to the top of the system stack. (use positive offset)
R14 (LR): Link Register. Holds the return address (PC + 4).
R15 (PC): Program Counter. Holds the address of the currently executing instruction.
When pushing LR or extra registers at the start of a nested
subroutine, the SP shifts. To recalculate LDR offsets:
Formula: New Offset = Old Offset + (Number of Extra Registers Pushed × 4
bytes)
Example: If a parameter was at [SP, #24] and you add LR to your push
list (STMFD SP!, R4-R7, LR), you pushed 1 extra register.
New offset = 24 + (1 × 4) = 28.
LDR R1, [R0], #4
MOV R2, R0
STMFD SP!, {R1, R2}
BL Sub1
Assuming R0=0x100, V1 stored at 0x100, V2 stored at 0x104.
R1 passed in by value, R2 passed in by reference.
Each recursive call saves the address of the next instruction using LR. To find number of recursive calls, find the number of repeated addresses saved, that are close to address in PC.