Assembly Programming
Assembly Programming
Assembly Programming
• Describe the syntax of assembly language instructions in the T32 instruction set
Some features of the Arm architecture may not be available through the compiler
• CMSIS provides intrinsics to access certain instructions
• Example: __WFI(); (implements WFI instruction)
Instructions consist of
• Opcode, destination register, first source operand, optional second source operand
OPCODE{<qualifier>}{<cond>} Rd, Rn, {Rm}
UAL also defines ‘pseudo’ instructions that are resolved by the Assembler
• The assembler will generate the machine code dependent upon the inline directives (e.g. .thumb) or the assembler switches (e.g. -mcpu)
The codes evaluate as TRUE or FALSE based on the values of the condition flags
The condition flags are part of the Application Program Status Register (APSR)
Disassembly rules
• One-to-one mapping is defined to ensure correct re-assembly
• .W or .N suffix used for cases when a bit pattern which doesn’t follow the above rules is disassembled
ADDSEQ.W r0, r1
ADDSEQ.W r0, r1
• Compare common C language source code sequences to their corresponding T32 instruction sequences
Logical
Operation Flags set? Result saved?
instruction
ANDS r0, r1, #0xA0 r0 = r1 & 0xA0 Only N, Z Yes
BIC r0, r1, #0xA0 r0 = r1 with bits 5 and 7 cleared No Yes
ORRS r0, r1, #0xA0 r0 = r1 | #0xA0 Only N, Z Yes
TST r1, #0xAB r1 & 0xAB Only N, Z No
Constants can be
• 8-bit number shifted left by any number of places
• In the form 0x00XY00XY, 0xXY00XY00 or 0xXYXYXYXY
Attempts to use constants which are not in the correct range will generate an assembly error
• Use the LDR pseudo-op – LDR Rn, =<constant>
• Assembler will use optimal sequence to generate constant into specified register
Logical inversion
Examples:
int op1, op2, op3, op4;
... Execute-only support: (-mexecute-only)
op1 = 0x2543;
MOV r0,#0x2543 • Data constants loaded into a register through a pair of
op2 = 0xFFFF43FF; instructions
MVN r1,#0x0000bc00
• Data side access to instruction memory not required
op3 = 0x2F008000;
MOVW r7,#0x8000
MOVT r7,#0x2F00 Literal pools:
op4 = 0xFFFFF5;
• Data constants, accessed through a PC relative load
LDR r3,.LCPI0_0
...
• Located near the code that uses them
.LCPI0_0 • Data side access to instruction memory required
.long 16777205 @ 0xfffff5
Examples:
int op1, op2, op3, dest1, dest2;
dest1 = op1 * op2;
MUL r8,r4,r5
dest2 = dest2 + op1 * op2;
MLA r9,r4,r5,r9
dest1 = dest1 – op2 * op3;
MLS r8,r5,r6,r8
24 1191 rev 35008
Divide
Armv8-M cores include division hardware
• Signed and unsigned divide are implemented using 32-bit instructions
struct REG1_t
{
unsigned int bit_05 : 6;
unsigned int bit_68 : 3;
unsigned int bit_9F : 7;
};
void test(void)
{
RegTemp1.bit_68 = RegTemp1.bit_9F; // UBFX r2,r1,#9,#7
// BFI r0,r2,#6,#3
}
26 1191 rev 35008
Bit manipulation instructions (2)
r1: LSB
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
width
dest, src, lsb, width
r2: UBFX r2, r1, #9, #7
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
zero-extend width
width
divideByTen:
movw r1, #52429
movt r1, #52428 divideByTen:
umull r0, r1, r0, r1 udiv r0, r0, #10
lsrs r0, r1, #3 bx lr
bx lr
Syntax
LDR{<size>}{<cond>} Rd, <address>
STR{<size>}{<cond>} Rd, <address>
Example
short *sptr = dest_addr; // r1
char *cptr = source_addr; // r0
*sptr = *cptr;
LDRB r0,[r0,#0]
STRH r0,[r1,#0]
Memory Memory
R0 R0
Pre-indexed Post-indexed
LDR R0, [R1, #12]! LDR R0, [R1], #12
#12 #12
+ R1 + R1
R1 R1
Memory Memory
Example
• LDM r10, {r0,r1,r4} ; load registers using r10 base
IA DB
r4
r1 Increasing
Base Register (Rb) r10 r0 Address
r4
r1
r0
34 1191 rev 35008
Stacks
Stack operations are implemented as multiple register transfers
• PUSH Store Multiple - Full Descending stack (STMFD, STMDB)
• POP Load Multiple - Full Descending stack (LDMFD, LDMIA)
Registers are stacked in order from lowest register to lowest memory location
• The order registers are specified has no effect
Stack should normally be kept 8-byte aligned on function entry for AAPCS compliance
Infinite loop!
ldrb r0, [r1, #1]! // increment pointer and load character from source
strb r0, [r2, #1]! // increment pointer and store character to destination
ldrb r0, [r1, #1]! // increment pointer and load character from source
strb r0, [r2, #1]! // increment pointer and store character to destination
ldrb r0, [r1, #1]! // increment pointer and load character from source
strb r0, [r2, #1]! // increment pointer and store character to destination
ldrb r0, [r1], #1 // load character from source, and then increment pointer
strb r0, [r2], #1 // and store character to destination, and then increment pointer
Branch Range
Instruction
16-bit 32-bit
func1 func2
void func1(void)
{
: :
BL func2 :
func2();
:
: BX lr
}
Syntax
• CB{N}Z <Rn>, <label>
– CBZ: If Rn is equal to zero, branch to label
– CBNZ: If Rn is not equal to zero, branch to label
. .
BEQ exit .
. .
exit exit
46 1191 rev 35008
If-Then block
Not enough bits in 16-bit or 32-bit Thumb encoding for conditional execution
; if (r0 == 0)
So IT instruction added, along with IT bits in xPSR ; r0 = *r1 + 2;
; else
Makes the next 1-4 instructions conditional ; r0 = *r2 + 4;
Syntax
• IT{T|E}{T|E}{T|E} <condition_code>
; if
• Any condition code may be used
CMP r0, #0
• Condition flags can change inside the block I T T E E EQ
; else
LDRNE r0, [r2]
ADDNE r0, #4
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
48 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
49 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
50 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
51 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
52 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
53 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
54 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
cmp r0, #1
blt L0
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
55 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
array dcd 0xF0000000, 0xF0000001, 0xF0000002
What C syntax could this code
lookup: correspond do?
mov r0, #2 // array index
ldr r1, =array // pointer to array Can you think of a more
cmp r0, #1 optimal way of performing this
blt L0 operation?
beq L1
bgt L2
L0:
ldr r0, [r1]
b exit
L1:
ldr r0, [r1, #4]
b exit
L2:
ldr r0, [r1, #8]
b exit
exit:
bx lr
56 1191 rev 35008
At the end of this instruction
Section quiz - Flow control sequence, what is the value in
register r0?
lookup:
mov r0, #2 // array index
ldr r1, =array // pointer to array
ldr r0, [r1, r0, lsl #2]
bx lr
armasm armclang
0x000 time
3 2 1 0 0 1 2 3
dest2 = __CLZ(dest3);
CLZ r1,r4
31 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 1 0 0 1 1 1 0 0 1 1 1 0 1 0 0
__WFI();
Wait For Interrupt – WFI WFI
• Puts the core into standby mode
• Woken by an interrupt or debug event
__WFE();
Wait For Event – WFE WFE
• Same as WFI, but will also wake the core on a signalled event
.global switch_to_psp
.type switch_to_psp, %function
switch_to_psp:
mrs r0, CONTROL // read the CONTROL register into r0
orr r0, r0, #0x2 // switch to the Process Stack Pointer
msr CONTROL, r0 // write r0 out to the CONTROL register
bx lr
The integer class instructions have a “dual” variant, whose result is 64-bit
CX2D p1, r0, r1, r5, #6 CX2DA p3, r3, r4, r8, #0xab