Move SMALL constants into a register:
mov r0, #C // Guaranteed to work for: -100 <= C <= 100
// OTHER constants CAN work;
// but not guaranteed
// Note: mov r0, #-1 ==> mvn r0, #0 !!! (neg 00000 --> 1111111)
Move LARGER constants (specially: addresses !!!) into a register:
// These 2 instructions TOGETHER will move 1234567 into reg r0
movw r0, #:lower16:1234567 //
// MOVW = MOVe Wide: moves a value into the lower half of reg
// #:lower16:1234567 = 1234567%(2^16) = lower 16 bits of 1234567
movt r0, #:upper16:1234567 //
// MOVT = MOVe Top: moves a value into the upper half of reg
// #:upper16:1234567 = 1234567/(2^16) = upper 16 bits of 1234567
You can use a label that marks a memory location (= address) for the constant:
movw r0, #:lower16:label // These 2 instructions will
movt r0, #:upper16:label // move address label into reg r0
Move the value in a simple memory variable into a register:
First move the address of the memory variable into a general purpose register:
movw r0, #:lower16:Label // r0 = memory address of the variable
movt r0, #:upper16:Label // at "Label"
Then use one of the following instructions depending on the data type:
(a) ldrsb r1, [r0] // Load a byte type variable and sign ext to int
// LDRSB = LoaD Register and Sign-extend Byte
(b) ldrsh r1, [r0] // Load a short type variable and sign ext to int
// LDRSH = LoaD Register and Sign-extend Half word
(c) ldr r1, [r0] // Load an int type variable
Move the value in a register (e.g.: r1) to a simple variable in memory:
First move the address of the memory variable into a general purpose register:
movw r0, #:lower16:Label // Set up memory address to variable
movt r0, #:upper16:Label // at "Label" in r0
Then use one of the following instructions depending on the data type:
(a) strb r1, [r0] // Store byte in reg r1 into memory location r0
// STRB = STore Register Byte
(b) strh r1, [r0] // Store short in reg r1 into memory location r0
// STRH = STore Register Half word
(c) str r1, [r0] // Store int in reg r1 into memory location r0
Move the array variable A[7] into a register:
First move the base address of the array into a general purpose register:
movw r0, #:lower16:A // r0 = address of label A
movt r0, #:upper16:A // = base address of array A
Depending on the data type of the array, multiply the index 4
with the size of array data type to get the offset:
byte typed array A, use offset: 7*1 = 7
short typed array A, use offset: 7*2 = 14
int typed array A, use offset: 7*4 = 28
Depending on the data type of the array A, use ldrsb, ldrsh or ldr
to fetch the array value A[4] into the register:
(a) byte array A: ldrsb r1, [r0, 7] // Base address + offset 7
(b) short array A: ldrsh r1, [r0, 14] // Base address + offset 14
(c) int array A: ldr r1, [r0, 28] // Base address + offset 28
Note:
To move the value in a register (e.g.: r2) to the array variable A[4],
you would do the same, except in the last step. You use
a store instruction - depending on the data type of the array A:
(a) strb r2, [r0, #7] // A[4] = r2 (byte value in r2)
(b) strh r2, [r0, #14] // A[4] = r2 (short value in r2)
(c) str r2, [r0, #28] // A[4] = r2 (whole reg r2)
Move the array variable A[i] into a register:
(1) First move the base address of the array into a general purpose register:
movw r0, #:lower16:A
movt r0, #:upper16:A
(2) Next move the index in variable i into another general purpose register:
movw r1, #:lower16:i // Get value i in r1
movt r1, #:upper16:i
To read the value in the index variable "i" into a register (r1),
use one of these instruction depending on data type of
the index variable "i",
(a) ldrb r1, [r1] // Load byte type variable i
(b) ldrh r1, [r1] // Load short type variable i
(c) ldr r1, [r1] // Load int type variable i
(3) Depending on the data type of the array, multiply the index value
in reg r1 by the size of array data type to get the offset.
Use one add instruction to multiply by 2:
add r1, r1, r1 // r1 = r1+r1 = 2*r1
Use 2 add instructions to multiply by 4:
add r1, r1, r1 // r1 = r1+r1 = 2*r1
add r1, r1, r1 // r1 = 2*r1+2*r1 = 4*r1
(4) Finally. use one of these instructions to load the
approriate amount of data from memory into reg r2
depending on the data type of the array A:
(a) ldrsb r2, [r0,r1] // r2 = A[i] (if A is byte array)
(b) ldrsh r2, [r0,r1] // r2 = A[i] (if A is short array)
(c) ldr r2, [r0,r1] // r2 = A[i] (if A is int array)
Note:
To move the value in a register (e.g.: r2) to the array variable A[i],
you would do the same, except in the last step. You use
a store instruction - depending on the data type of the array A:
(a) strb r2, [r0,r1] // A[i] = r2 (byte value in r2)
(b) strh r2, [r0,r1] // A[i] = r2 (short value in r2)
(c) str r2, [r0,r1] // A[i] = r2 (whole reg r2)
Move some component in an object into a register:
1. fetch the base address of the object inside a register (e.g.: r0)
E.g.: ptr points to an object (e.g. list)
movw r0, #:lower16:ptr
movt r0, #:upper16:ptr
ldr r0, [r0]
2. Find the OFFSET of the component in the object
from its CLASS definition
Say this offset is X
Depending on the data type of the component, fetch the
component into a register using:
(a) ldrsb r1, [r0, #X] // if component type is byte
(b) ldrsh r1, [r0, #X] // if component type is short
(c) ldr r1, [r0, #X] // if component type is int
Arithmetic operations:
add r2, r1, r0 // r2 = r1 + r0
add r2, r1, #4 // r2 = r1 + 4
sub r2, r1, r0 // r2 = r1 - r0
sub r2, r1, #4 // r2 = r1 - 4
rsb r2, r0, #0 // r2 = 0 - r0 (reverse subtraction)
// sub r0, r1, r2 = r0 = r1 - r2
// rsb r0, r1, r2 = r0 = r2 - r1 (reverse sub)
// Useful: negate a value !!!
mul r2, r1, r0 // r2 = r1 * r0
mul r2, r1, #4 // ILLEGAL !!!
// CANNOT use a constant as 2nd source !!!
mul r1, r1, r2 // ILLEGAL !!!
// CANNOT use same src1 and dest register !!!
* The ARM processor does NOT have a divide instruction !!!
(You call a subroutine in the run time library to perform division)
Compare and branch:
cmp r0, #4 // Compare r0 against 4
bCC Label // Branch to location Label if r0 CC r1
// bCC can be: beq, bne, blt, ble, bgt, bge
cmp r0, r1 // Compare r0 against r1
bCC Label // Branch to location Label if r0 CC r1
The conditional branch instructions are:
beq bne blt ble bgt bge
UNconditional branch:
b Label // Branch to location Lable UNCONDITIONALLY
Subroutine call
bl Label // Branch and link
// Stores return address in reg "lr" (r14)
How to save return address (in reg "lr") on the system stack:
push {lr}
Subroutine return without saving return address on system stack:
mov pc, lr // PC := lr
Subroutine return after saving return address on system stack:
pop {pc} // Pop return address from system stack into PC
Parameter passing and local variables in stack frame:
Pass a parameter: push {r0} // MUST use register in push
// So: put the parameter in a register
// before pushing
Pop a parameter: add sp, sp, #4 // Pops 4 bytes off the stack
Subroutine construct summary:
Subroutine Prelude:
push {lr} // Save return address
push {fp} // Save frame pointer
mov fp, sp // Set up my stack frame pointer
sub sp, sp, #8 // 2 int locals
Access parameters:
ldr .., [fp, #8] // First int parameter
ldr .., [fp, #12] // Second int parameter
Access local variables:
ldr .., [fp, #-4] // First int variable
ldr .., [fp, #-8] // Second int variable
Subroutine Postlude:
mov sp, fp // Pop locals
pop {fp} // Restore stack frame pointer
pop {pc} // Return
|