0% found this document useful (0 votes)
4 views107 pages

Unit 04_AD-ARM Assembly Language

This document covers ARM assembly language instructions, focusing on data movement, memory addressing modes, and endianness. It details various mnemonics used for moving data between registers and memory, as well as techniques for loading and storing multiple words. Additionally, it discusses memory alignment and the differences between little-endian and big-endian data storage formats.

Uploaded by

ayaanmunshi456
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views107 pages

Unit 04_AD-ARM Assembly Language

This document covers ARM assembly language instructions, focusing on data movement, memory addressing modes, and endianness. It details various mnemonics used for moving data between registers and memory, as well as techniques for loading and storing multiple words. Additionally, it discusses memory alignment and the differences between little-endian and big-endian data storage formats.

Uploaded by

ayaanmunshi456
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

ECE3375B: Microprocessors and Microcomputers

Electrical and Computer Engineering


Western University

Unit 4: ARM Assembly Language


Types of Instructions used in Assembly Language
• This section reviews types of instructions used in assembly language and
provide specifics for ARMv7 assembly language.

The basic categories of assembly language instructions are:


1. Data movement instructions.
2. Data manipulation instructions.
3. Conditionals and test instructions.
4. Branch instructions.
5. Subroutine instructions.
6. Interrupt instructions.

• The last two categories will be examined in a future lesson.


Data Movement Instructions
There are three basic instructions for data movement:
1. moving data between registers,
2. moving data from memory into a register, and
3. moving data from a register into memory.
• To move data between registers, the mov mnemonic is used. Two operands
are always required, the first is the register the data is moved into, the second
is the register the data is moved from or can be a numerical value .
Example1: What does the following commands do?
mov r0 , #98 moves the number 98 to register r0
mov r1 , r0 moves the data stored in r0 to register r1

• mov can only load a 12-bit constant into a register.


• ldr can load a 32-bit constant to a register.
Data Movement Instructions
• To load data into a register from memory, use the ldr mnemonic. Two operands
are always required, the first is the register the data is moved into, the second
is address in memory that the data is moved from.
• Using a register as the second operand will always use the value in that
register as data. To use it as an address, enclose it in square brackets.
This is needed for str and ldr commands.

Example 2: ldr r1 , [r0] If r0 stores 0x82000004 corresponding to an


address location.
Loads a word (4 bytes) in r1 from memory at
address 0x82000004.
Data Movement Instructions
Example 3: ldr r1 , big_word R1 stores 53400524 (Pseudo
instruction. The compiler will
big_word: .word 53400524 translate it to actual machine code)

Example 4: ldr r1 , =0xff200020 Loads the hexadecimal number


0xff200020 in register r1
Data Movement Instructions
• To store data from a register into memory, use the str mnemonic. Two
operands are always required, the first is the register the data is moved from,
the second is address in memory that the data is moved into.

Example 5: str r0 , [r1] Stores the value in r0 into the


memory address contained in r1:
Memory Addressing Modes
• Reading and writing ordered lists (or arrays) of data is a common process in
computer programming.
• To simplify this in assembly language, there are additional ways to load and
store data to/from the address in memory.
1. Addressing with an offset refers to accessing a memory element that is a given
distance from the base address.
2. Pre-indexed addressing refers to changing the base address in the register
before looking up the memory element at the new address.
3. Post-indexed addressing refers to looking up the memory element at the
present address in the register, then shifting the address stored in that register.
• These techniques are useful for reading/writing arrays of data, or for
interacting with some memory-mapped I/O peripherals. These techniques
work with any instruction that uses a register value as an address.
Memory Addressing Modes
Example 6: What does each line do?
Initializes register r1 with the value 10.
mov r1 , #10
ldr r0 , =0x00ff1000 Initializes register r0 with the memory
address 0x00ff1000
str r1 , [r0]
str r1 , [r0 , #4] Direct addressing is used to write the number 10
str r1 , [r0 , #4 ]! to the memory address 0x00ff1000.
str r1 , [r0], #4

Addressing with an offset is used to write the number


10 to the memory address 0x00ff1004. The content of
register r0 is still 0x00ff1000.
Memory Addressing Modes
Example 6
Pre-indexed addressing is used to write the number
mov r1 , #10 10 to the memory address 0x00ff1004. The content
ldr r0 , =0x00ff1000 of register r0 is changed to 0x00ff1004.
str r1 , [r0]
str r1 , [r0 , #4] Post-indexed addressing is used to write the
str r1 , [r0 , #4 ]! number 10 to the memory address 0x00ff1004.
str r1 , [r0], #4 The content of register r0 is then changed to
0x00ff1008.

• Because pre-indexing and post-indexing change the base address, they can
be used to efficiently cycle through an array of data.
Memory Alignment
• The memory width of a microcontroller is often smaller than the word size of
the microprocessor
• This is the case with the ARM®Cortex-A9: the registers are 4 bytes, but the
memory cells are only 1 byte wide.

mov r1 , #10 • The data movement instructions discussed are


ldr r0 , =0x00ff1000 all based on manipulating a word of data.
str r1 , [r0]
str r1 , [r0 , #4] • Consequently, in the provided examples, addresses
str r1 , [r0 , #4 ]! are always given, and incremented, in multiples of
str r1 , [r0], #4 4 bytes.
Memory Alignment
Because of difference in memory width and register width, it is important to
keep data aligned in memory.

To help protect data and instruction sets from becoming misaligned, the
following rules must be obeyed:
• Data stored as words (32 bits) can only be at addresses that are integer
multiples of 4.
• Data stored as half-words (16 bits) can only be at addresses that are integer
multiples of 2.

• Data stored as bytes (8 bits) can be at any address.


Memory Alignment
Example
mov r1 , #1
ldr r0 , =0x00ff1000
str r1 , [r0] This command uses 4 sequential bytes of
memory to store the number one.

• Reading from, or writing to, these 4 sequential bytes is handled automatically


by the ldr and str commands.

• If the address stored in r0 is not a multiple of 4, executing this code in a


simulator will generate an error message in some processors.
Memory Alignment
Example 7: What are the memory address offsets for AVECTROR
Words, Half-Words, & Endianness
• Storing numbers across multiple memory cells also raises the problem of
endianness: in what order do the contents of each memory cell combine to
make the large number?
• Consider storing the number 0x1A2B in a system with a 16-bit address space
and 8-bit memory cells, starting at address 0x1000. There are two ways to
store this number, as shown below.

The order of (a) is referred to as


big-endian, and the order of (b) is
little-endian.
Words, Half-Words, & Endianness
Definitions
• A computer system is big endian if the most significant byte in a larger
number is stored at the lowest memory address.
• A computer system is little endian if the most significant byte in a larger
number is stored at the highest memory address.
There are reasonable arguments for and against both methods of storing data.

• As shown in Figure, the big endian


is easier for a human to read.

Two ways to order bytes in memory for the half-word 0x1A2B:


Little Endian vs Big Endian
MSB LSB
Byte 3 Byte 2 Byte 1 Byte 0

High address High address


Byte 3 Byte 0

Byte 2 Byte 1

Byte 1 Byte 2
Byte 0 LSB MSB Byte 3
Low address Low address

Little Endian Big Endian

LSB is at least address! MSB is at least address!


Words, Half-Words, & Endianness
• Little endian is logically more sensible, because the least significant byte is
stored at the lowest memory address, and the most significant byte is
stored at the highest memory address.
• However little endian is less human readable.

• By default, ARM processors are little endian, although they can be


reconfigured to big endian if necessary

• If two microprocessors with different conventions need to exchange data,


however, then some kind of hardware or software conversion is required to
ensure data is read correctly by each system.
Little Endian vs Big Endian
Example 8: Describe how the numerical value of 0xA7908CEE is placed in memory
at address 0x20008000 if
a) Little endian is used.
b) Big endian is used.
Example 9: The value stored in memory is shown.
What is the numerical value read from memory if
a) Little endian is used.
b) Big endian is used.
Loading and Storing Half-Words & Bytes
• As mentioned previously, the mnemonics str and ldr are all based on
manipulating a word (32 bits) of data.
• Sometimes it is required to access the contents of only a single byte or 16-bit
half-words.

• To load a single byte from memory, use the ldrb mnemonic.


▪ All unused bits in the register are filled with zeros
▪ Any integer can be used as the memory address, not just integers
evenly divisible by 4.
▪ Otherwise, this mnemonic is the same as the ldr mnemonic discussed
previously.
Loading and Storing Half-Words & Bytes
• To store a single byte to memory, use the strb mnemonic.
▪ Any integer can be used as the memory address, not just integers
evenly divisible by 4.
▪ Otherwise, this mnemonic is the same as the str mnemonic discussed
previously.

• To load a half-word from memory, use the ldrh mnemonic.


▪ All unused bits in the register are filled with zeros.
▪ Any even integer can be used as the memory address, not just
integers evenly divisible by 4.
▪ Otherwise, this mnemonic is the same as the ldr mnemonic discussed
previously.
Loading and Storing Half-Words & Bytes
• To store a half-word to memory, use the strh mnemonic
▪ Any even integer can be used as the memory address, not just integers
evenly divisible by 4.
▪ Otherwise, this mnemonic is the same as the str mnemonic discussed
previously.

• When loading a word, it is irrelevant whether the data is signed or unsigned

• However, since the CPU registers are all 32-bits, it is important to know
whether the data is signed or unsigned when loading a half-word or a byte.
Loading and Storing Half-Words & Bytes
• The representation of a signed number depends on the number of bits
available.
• For example, (−7)10 is represented in 8-bits as 0b1111 1001 (using 2’s-
complement convention).
• In 32-bits it is 0b1111 1111 1111 1001.
• Clearly for a signed negative number, all higher-order, unused bits in the
register should be flipped to 1.
• For this reason, there are special mnemonics for loading signed bytes and
half-words.
Loading and Storing Half-Words & Bytes
• To load a single signed byte from memory, use the ldrsb mnemonic.
• To load a signed half-word from memory, use the ldrsh mnemonic.

• The ARMv7 language has mnemonics for storing signed bytes and signed
half-words as well (namely, strsb and strsh) but the user manual states that
these function exactly the same as an unsigned store.
Loading and Storing Multiple Words
• Sometimes it is useful to load and store multiple words of data.
• Each register can only store a single word, so in principle this is just done
by applying ldr or str multiple times to different registers.
• However, to streamline this process there is the option to move words to
or from a set of registers and a sequential range of memory.
• To load multiple words from a sequential range in memory to a set of
registers use the ldmia, ldmda, ldmib, or ldmdb mnemonics.
▪ Unusually, the first operand is the register containing the base address
in memory, and this operand should be preceded by a !.
▪ The second operand is a set of brace brackets with a list of registers to
load data into: such as {r0,r1,r3}.
Loading and Storing Multiple Words
• ldmia, ldmda, ldmib, or ldmdb mnemonics.

• “Increment” means the base address is increased


by 4 after loading/storing each register.
• “decrement” means the base address is decreased
by 4 after loading/storing each register.

• “After” means this address shift occurs after loading/storing to each register.
• “before” means this address shift occurs prior to loading/storing to each
register.
Loading and Storing Multiple Words
• To store multiple words from a sequential range in
memory to a set of registers use the stmia, stmda,
stmib, or stmdb mnemonics.

▪ The stmia, stmda, stmib, or stmdb mnemonic has


the same syntax as that for loading multiple words
Example 10: Describe what the following code does?
ldr r0 , =0x2000 Loads a memory address into register r0.
mov r1 , #12 Initialize registers, r1, r2, and r3 with values.
mov r2 , #140
mov r5 , #10 The values of register r1, r2, and r3 are
stmia r0!, {r5 , r1 , r2} written to memory.
Loading and Storing Multiple Words

ldr r0 , =0x2000 • The ARMv7 assembler always sorts the registers in


mov r1 , #12 ascending numerical order.
mov r2 , #140
• So r1 is stored to memory at the lowest address and
mov r5 , #10
r5 is stored to memory at the highest address,
stmia r0!, {r5 , r1 , r2} regardless of how the registers are listed or whether
the store operation is incrementing or decrementing.

• r1 is stored to the address 0x2000, r2 is then stored to address 0x2004, and


r5 is stored to address 0x2008.
• After this operation is completed, r0 holds the value 0x200C.
Loading and Storing Multiple Words
Example 11: Describe what the following code does?

ldr r0 , =0x2000 If the following command is executed next


mov r1 , #12 • The data in memory starting at the address in
mov r2 , #140 r0 (0x200C) is loaded into the registers.
mov r5 , #10
stmia r0!, {r5 , r1 , r2} • Again, the ARMv7 assembler always sorts
ldmda r0!, {r2 , r1 , r5} the registers, but this time in descending
numerical order.

• so r5 will be loaded the base address first (as it


is at the highest address), and r1 is loaded from
memory last (as it is at the lowest address).
Loading and Storing Multiple Words
ldr r0 , =0x2000 • this means r5 will read the value stored in memory
mov r1 , #12 at 0x200C, r2 the value stored in memory at 0x2008,
mov r2 , #140 and r1 the value stored in memory at 0x2004.
mov r5 , #10 • After this operation is completed, r0
stmia r0!, {r5 , r1 , r2} again holds the value 0x2000.
ldmda r0!, {r2 , r1 , r5}

• Assuming memory location 0x200C


stored 0x2F (47 decimal).

• r1 stores 0x8C (140 decimal),


• r2 stores 0xA (10 decimal) and
• r5 stores 0x2F (47 decimal) address.
Loading and Storing Multiple Words
Example 12: Describe what the following code does?
ldr r0 , =0x2000
mov r1 , #12 • Here the ldmda command is replaced with
mov r2 , #140 ldmdb
mov r5 , #10
stmia r0!, {r5 , r1 , r2} • Result in this code is registers r1, r2 and r3
ldmdb r0!, {r2 , r5 , r1} have the same values as when the code
started.

• What is the usefulness of these commands?


Loading and Storing Multiple Words
What is the usefulness of these commands?
• In a higher-level code (C, Java, Python, etc.) you can always define extra user
variables whenever you want.
• In assembly, however, you are limited by the number of registers that
physically exist in the CPU architecture.
• If your program needs to perform some complicated calculation, and requires
space for temporary variables, you can perform
stmia r7! {r0 - r5}
(for example) to store the contents of several registers to memory.
• Then your program can use registers r0 to r5 for the complicated calculation.
• After obtaining the results, your program can restore it’s original state (i.e.
overwrite the temporary variables with the original values) using
ldmdb r7! {r0 - r5}.
Loading and Storing Multiple Words
Example 13: Describe what the following code does?

ldr r0 , =0x1010
Stores r1, r2, r3 and r4 to stmdb r0!, {r1 - r4}
memory and r0 = 0x1000 …
Loads from memory r1, r2, ldmia r0!, {r1 - r4}
r3 and r4 and r0 = 0x1010
Loading and Storing Multiple Words
Example 14: Describe what the following code does?

ldr r0 , =0x1010
Stores r1, r2, r3 and r4 to stmda r0!, {r1 - r4}
memory and r0 = 0x1000 …
Loads from memory r1, r2, ldmib r0!, {r1 - r4}
r3 and r4 and r0 = 0x1010
Loading and Storing Multiple Words
Example 15: Describe what the following code does?

ldr r0 , =0x1010
Stores r1, r2, r3 and r4 to stmib r0!, {r1 - r4}
memory and r0 = 0x1020 …
Loads from memory r1, r2, ldmda r0!, {r1 - r4}
r3 and r4 and r0 = 0x1010
Loading and Storing Multiple Words
Example 16: Describe what the following code does?

ldr r0 , =0x1010
Stores r1, r2, r3 and r4 to stmia r0!, {r1 - r4}
memory and r0 = 0x1020 …
Loads from memory r1, r2, ldmdb r0!, {r1 - r4}
r3 and r4 and r0 = 0x1010
Data Manipulation Instructions
The basic ways of manipulating and comparing data are by arithmetic
operations, logic operations, and bit shifting.
• Arithmetic and logic operations use the arithmetic logic unit (ALU) in the
microprocessor to manipulate the contents of one or two registers.
• Bit shifting can also use the ALU, but in ARMv7 architecture a special piece
of hardware called the barrel shifter is often used.
• Most microprocessors support addition, subtraction, multiplication, and
division. Multiplication and division will not be discussed in this course.
Data Manipulation Instructions
• To add two numbers together, use the add mnemonic.
• Two operands are always required, and the first one must be a register.
• Three operands may also be given, in which case the first two must be
registers

• If two operands are given, the two values corresponding to each operand are
added together and the result is stored in the first operand (which must be a
register), overwriting the previous value.
• If three operands are given, the values of the last two operands are added
together and stored in the first.
Data Manipulation Instructions
• To subtract one number from another, use the sub mnemonic.
• Two or three operands can be provided. The sub mnemonic works exactly
the same way as add, except it performs subtraction instead of addition.

• To reverse subtract one number from another, use the rsb mnemonic.
• Two or three operands can be provided, and rsb works similarly to add and
sub.
Data Manipulation Instructions
Example 17: Describe operations
add r1 , r2 , r3 @ compute r1=r2 +r3
add r1 , r2 @ compute r1=r1 +r2
add r1 , #4 @ compute r1=r1 +4

• In the above examples, the last two lines of code cause the contents of r1 to
be overwritten.

add #17 , r1 @ causes a compiler error since first operand is


@ not a register
Data Manipulation Instructions
Example 18: Describe operations of sub and rsb:

sub r1 , #12 @ compute r1=r1-12


rsb r1 , #12 @ compute r1=12-r1
sub r1 , r2 , r3 @ compute r1=r2-r3
rsb r1 , r3 , r2 @ compute r1=r2-r3

• Note, the last two lines are identical.

• The main use for rsb is when you are using a literal (like #12 in the above
example) instead of a register for the subtraction.
Overview: Arithmetic and Logic Instructions
Commonly Used Arithmetic Operations
ADD {Rd,} Rn, Op2 Add. Rd  Rn + Op2
ADC {Rd,} Rn, Op2 Add with carry. Rd  Rn + Op2 + Carry
SUB {Rd,} Rn, Op2 Subtract. Rd  Rn - Op2
SBC {Rd,} Rn, Op2 Subtract with carry. Rd  Rn - Op2 + Carry - 1
RSB {Rd,} Rn, Op2 Reverse subtract. Rd  Op2 - Rn
MUL {Rd,} Rn, Rm Multiply. Rd  (Rn × Rm)[31:0]
Multiply with accumulate.
MLA Rd, Rn, Rm, Ra
Rd  (Ra + (Rn × Rm))[31:0]
MLS Rd, Rn, Rm, Ra Multiply and subtract, Rd  ((Rn × Rm) – Ra)[31:0]
SDIV {Rd,} Rn, Rm Signed divide. Rd  Rn / Rm
UDIV {Rd,} Rn, Rm Unsigned divide. Rd  Rn / Rm

 Syntax
<Operation>{<cond>}{S} Rd, Rn, Operand2 {,shift #s}
Example 19: Short Multiplication

; MUL: Signed multiply


MUL r6, r4, r2 ; r6 = LSB32( r4 × r2 )

; UMUL: Unsigned multiply


UMUL r6, r4, r2 ; r6 = LSB32( r4 × r2 )

; MLA: Multiply with accumulation


MLA r6, r4, r1, r0 ; r6 = LSB32( r4 × r1 ) + r0

; MLS: Multiply with subtract


MLS r6, r4, r1, r0 ; r6 = LSB32( r4 × r1 ) - r0

LSB32: register holds the Least significant 32 bits


Example 20: Long Multiplication
Unsigned long multiply
UMULL RdLo, RdHi, Rn, Rm
RdHi,RdLo  unsigned(Rn × Rm)

Signed long multiply


SMULL RdLo, RdHi, Rn, Rm
RdHi,RdLo  signed(Rn × Rm)
Unsigned multiply with accumulate
UMLAL RdLo, RdHi, Rn, Rm
RdHi,RdLo  unsigned(RdHi,RdLo + Rn × Rm)

Signed multiply with accumulate


SMLAL RdLo, RdHi, Rn, Rm
RdHi,RdLo  signed(RdHi,RdLo + Rn × Rm)

The result has 64 bits, placed in two registers.

UMULL r3, r4, r0, r1 ; r4:r3 = r0  r1, r4 = MSB bits, r3 = LSB bits
SMULL r3, r4, r0, r1 ; r4:r3 = r0  r1
UMLAL r3, r4, r0, r1 ; r4:r3 = r4:r3 + r0  r1
SMLAL r3, r4, r0, r1 ; r4:r3 = r4:r3 + r0  r1
Bitwise Logic
Bitwise logic AND
AND {Rd,} Rn, Op2
Rd  Rn & operand2
Bitwise logic OR
ORR {Rd,} Rn, Op2
Rd  Rn | operand2
Bitwise logic exclusive OR
EOR {Rd,} Rn, Op2
Rd  Rn ^ operand2
Bitwise logic NOT OR
ORN {Rd,} Rn, Op2
Rd  Rn | (NOT operand2)
Bit clear
BIC {Rd,} Rn, Op2
Rd  Rn & NOT operand2
Bit field clear
BFC Rd, #lsb, #width
Rd[(width+lsb–1):lsb]  0
Bit field insert
BFI Rd, Rn, #lsb, #width
Rd[(width+lsb–1):lsb]  Rn[(width-1):0]
Move NOT, logically negate all bits
MVN Rd, Op2
Rd  0xFFFFFFFF EOR Op2
Example 21: AND r2, r0, r1
32 bits
r0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
r1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1

r2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

Bit-wise Logic AND


Example 22: BIC r2, r0, r1
r2 = r0 & NOT r1

Step 1:
r1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
NOT r1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0

Step 2:
r0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
NOT r1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0

r2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
Example: BFC and BFI
• Bit Field Clear (BFC) and Bit Field Insert (BFI).
• Syntax
• BFC Rd, #lsb, #width
• BFI Rd, Rn, #lsb, #width

• Examples 23: Describe the following two commands


BFC R4, #8, #12
; Clear bit 8 to bit 19 (a total of 12 bits) of R4

BFI R9, R2, #8, #12


; Replace bit 8 to bit 19 (12 bits) of R9
; with bit 0 to bit 11 from R2.
Reverse Order
Reverse bit order in a word
RBIT Rd, Rn
for (i = 0; i < 32; i++) Rd[i]  RN[31– i]
Reverse byte order in a word
REV Rd, Rn Rd[31:24]  Rn[7:0], Rd[23:16]  Rn[15:8],
Rd[15:8]  Rn[23:16], Rd[7:0]  Rn[31:24]
Reverse byte order in each half-word
REV16 Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:24]  Rn[23:16], Rd[23:16]  Rn[31:24]
Reverse byte order in bottom half-word and sign extend
REVSH Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:16]  Rn[7] & 0xFFFF

RBIT Rd, Rn
Rn

Rd

Example 24: Describe the following commands


LDR r0, =0x12345678 ; r0 = 0x12345678
RBIT r1, r0 ; Reverse bits, r1 = 0x1E6A2C48
Reverse Order
Reverse bit order in a word
RBIT Rd, Rn
for (i = 0; i < 32; i++) Rd[i]  RN[31– i]
Reverse byte order in a word
REV Rd, Rn Rd[31:24]  Rn[7:0], Rd[23:16]  Rn[15:8],
Rd[15:8]  Rn[23:16], Rd[7:0]  Rn[31:24]
Reverse byte order in each half-word
REV16 Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:24]  Rn[23:16], Rd[23:16]  Rn[31:24]
Reverse byte order in bottom half-word and sign extend
REVSH Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:16]  Rn[7] & 0xFFFF

REV Rd, Rn
Rn

Rd

Example 25: Describe the following commands


LDR R0, =0x12345678 ; R0 = 0x12345678
REV R1, R0 ; R1 = 0x78563412
Reverse Order
Reverse bit order in a word
RBIT Rd, Rn
for (i = 0; i < 32; i++) Rd[i]  RN[31– i]
Reverse byte order in a word
REV Rd, Rn Rd[31:24]  Rn[7:0], Rd[23:16]  Rn[15:8],
Rd[15:8]  Rn[23:16], Rd[7:0]  Rn[31:24]
Reverse byte order in each half-word
REV16 Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:24]  Rn[23:16], Rd[23:16]  Rn[31:24]
Reverse byte order in bottom half-word and sign extend
REVSH Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:16]  Rn[7] & 0xFFFF

REV16 Rd, Rn
Rn

Rd

Example 26: Describe code


LDR R0, =0x12345678 ; R0 = 0x12345678
REV16 R2, R0 ; R2 = 0x34127856
Reverse Order
Reverse bit order in a word
RBIT Rd, Rn
for (i = 0; i < 32; i++) Rd[i]  RN[31– i]
Reverse byte order in a word
REV Rd, Rn Rd[31:24]  Rn[7:0], Rd[23:16]  Rn[15:8],
Rd[15:8]  Rn[23:16], Rd[7:0]  Rn[31:24]
Reverse byte order in each half-word
REV16 Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:24]  Rn[23:16], Rd[23:16]  Rn[31:24]
Reverse byte order in bottom half-word and sign extend
REVSH Rd, Rn Rd[15:8]  Rn[7:0], Rd[7:0]  Rn[15:8],
Rd[31:16]  Rn[7] & 0xFFFF

REVSH Rd, Rn
Rn

Rd

Example 27: Describe code


LDR R0, =0x33448899 ; R0 = 0x33448899
REVSH R1, R0 ; R1 = 0xFFFF9988
Sign and Zero Extension
int8_t a = -1; // a signed 8-bit integer, a = 0xFF
int16_t b = -2; // a signed 16-bit integer, b = 0xFFFE
int32_t c; // a signed 32-bit integer

c = a; // sign extension required, c = 0xFFFFFFFF


c = b; // sign extension required, c = 0xFFFFFFFE
Sign and Zero Extension
Sign extend a byte
SXTB {Rd,} Rm {,ROR #n}
Rd[31:0]  Sign Extend((Rm ROR (8 × n))[7:0])
Sign extend a half-word
SXTH {Rd,} Rm {,ROR #n}
Rd[31:0]  Sign Extend((Rm ROR (8 × n))[15:0])
Zero extend a byte
UXTB {Rd,} Rm {,ROR #n}
Rd[31:0]  Zero Extend((Rm ROR (8 × n))[7:0])
Zero extend a half-word
UXTH {Rd,} Rm {,ROR #n}
Rd[31:0]  Zero Extend((Rm ROR (8 × n))[15:0])

Example 28: Describe code


LDR R0, =0x55AA8765
SXTB R1, R0 ; R1 = 0x00000065
SXTH R1, R0 ; R1 = 0xFFFF8765
UXTB R1, R0 ; R1 = 0x00000065
UXTH R1, R0 ; R1 = 0x00008765
Sign and Zero Extension
Example 29: Convert C code to assembly
int8_t a = -1; // a signed 8-bit integer, a = 0xFF
int16_t b = -2; // a signed 16-bit integer, b = 0xFFFE
int32_t c; // a signed 32-bit integer

c = a; // sign extension required, c = 0xFFFFFFFF


c = b; // sign extension required, c = 0xFFFFFFFE
Move Data between Registers
MOV Rd, operand2 Rd  operand2
MVN Rd, operand2 Rd  NOT operand2
MRS Rd, spec_reg Move from special register to general register
MSR spec_reg, Rm Move from general register to special register

Example 30: Describe code

MOV r4, r5 ; Copy r5 to r4


MVN r4, r5 ; r4 = bitwise logical NOT of r5
MOV r1, r5, LSL #3 ; r1 = r5 << 3
MOV r0, PC ; Copy PC (r15) to r0
MOV r1, SP ; Copy SP (r14) to r1
Move Immediate Number to Register
MOVW Rd, #imm16 Move Wide, Rd  #imm16

MOVT Rd, #imm16 Move Top, Rd  #imm16 << 16

MOV Rd, #const Move, Rd  const

Example 31: Load a 32-bit number into a register


MOVW r0, #0x4321 ; r0 = 0x00004321
MOVT r0, #0x8765 ; r0 = 0x87654321

• MOVW will zero the upper halfword


• MOVT won’t zero the lower halfword
Order does matter!

MOVT r0, #0x8765 ; r0 = 0x8765xxxx


MOVW r0, #0x4321 ; r0 = 0x00004321
Data Manipulation and Status Flags
• The four most significant bits of the current program status register (cpsr)
are flags that can be returned by the ALU.

• Bit 31 of the cpsr is the negative flag (N), which is set to 1 if a signed
arithmetic operation returns a negative answer.
• Bit 30 of the cpsr is the zero flag (Z), which is set to 1 if the result of an
arithmetic operation is zero.
• Bit 29 of the cpsr is the carry flag (C), which is set to 1 if an unsigned addition
overflow occurred and cleared to 0 if an unsigned subtraction “underflow”
(also called a borrow) occurred.0
• Bit 28 of the cpsr is the overflow flag (V), which is set to when a signed
addition or subtraction caused the sign of the result to be changed improperly.
Data Manipulation and Status Flags

• These status flags are important for determining whether an arithmetic


operation produced a valid result.
• They are also important for performing comparisons between two numbers.
• For example, to test if A > B, we can just perform the subtraction A − B, ignore
the result, and examine the carry flag (in this case, acting as a borrow).
A and B are unsigned numbers: If A-B is positive Carry flag = 1 (no borrow)
If A-B is negative Carry flag = 0 (borrow)
• However, the status flags are not always set by a data manipulation
instruction. The mnemonics only set the status flags when “s” is appended
the command as adds, subs, and rsbs.
Comparisons and Conditional Execution
• To compare two numbers, use the cmp mnemonic.
• This mnemonic requires two operands, the first of which must be a register.
• The cmp mnemonic is functionally the same as subtracting the two numbers
and discarding the result, but updating the status flags
Example 32: Discuss how these two commands change status flags
cmp r0 , r1 @ calculate r0-r1 , discard answer
subs r2 , r0 , r1 @ same as above but keep answer

• Once the status flags are set, a two-letter conditional execution code can be
appended to almost any mnemonic.

• This will mean that mnemonic is only executed under certain conditions.
Comparisons and Conditional Execution
Two examples are provided:

• To conditionally add two numbers only when a previous comparison


demonstrated that two numbers were equal, use the addeq mnemonic.
• This mnemonic is otherwise identical to the add mnemonic.

• To conditionally write a number to memory only when a previous comparison


demonstrated that one number was greater than another, use the strge
mnemonic.
• This mnemonic is otherwise identical to the str mnemonic.
Comparisons and Conditional Execution

Table A: List of conditional execution codes, which will be true when the condition for two
numbers x and y given in the description is valid. Many conditionals have different codes
depending on whether the test is with signed or unsigned numbers.
Comparisons and Conditional Execution
• cmp may not be the most convenient mnemonic for testing a condition.
• Sometimes it is more efficient to use a data manipulation step to
update/change the status flags (with adds or subs, for example).
• Then we just need the status flags updated to perform a condition test.

• However, it is also important to avoid updating the status flags when


performing multiple conditional executions based on the same original
test case. (This is illustrated in the next example)
Comparisons and Conditional Execution
Example 33: Describe the following code

mov r1 , #10 @ r1 and r2 are initialized with data


mov r2 , #25
ldr r3 , =0x100 @ r3 is initialized with an address
cmp r1 , r2 @ the values of r1 and r2 are compared
addhi r1 , #2 @ If r1 > r2, then r1 is increased by 2.
sublos r1 , #2 @ If r1 < r2, then r1 is further decreased by 2
@ mnemonic ends with ‘s’, the status flags are reset!
strlo r1 , [r3] @ The value in r1 is stored in memory, but only if r1 < 2
Comparisons and Conditional Execution

Table A: List of conditional execution codes, which will be true when the condition for two
numbers x and y given in the description is valid. Many conditionals have different codes
depending on whether the test is with signed or unsigned numbers.
Comparisons and Conditional Execution
mov r1 , #10 • Since 10 < 25, the addition will not occur, but the
mov r2 , #25 subtraction will.
ldr r3 , =0x100 • As we used sublos instead of sublo, this subtraction
cmp r1 , r2 will overwrite the status flags from the original cmp
addhi r1 , #2 • Although we (probably) intended to write r1 to
sublos r1 , #2 memory as 10 < 25, instead this will not occur: the
strlo r1 , [r3] condition flags are based on the subtraction 10 − 2,
and as 10 > 2, the “less than condition for unsigned
numbers” will evaluate as false.
Comparisons and Conditional Execution
There are also three other commands that can also be used for comparisons.
• To compare a number and the negative of another number, use the cmn
mnemonic.
• This mnemonic requires two operands, the first of which must be a register.

• To test two numbers, use the tst mnemonic.


• This mnemonic requires two operands, the first of which must be a register.

• To test the equivalence of two numbers, use the teq mnemonic.


• This mnemonic requires two operands, the first of which must be a register.

• cmn, tst and teq are basically the similar as cmp, in which an arithmetic or
logical operation is applied to both numbers, the status flags are updated,
and the result of the operation is discarded.
Comparisons and Conditional Execution
• The cmn mnemonic is functionally the same as adding two numbers and
discarding the result.
• If one of these numbers is the 2’s compliment of the other, the sum will add
to zero—hence the name “compare negative” for this mnemonic.
• The tst mnemonic is functionally the same as performing the bitwise AND of
the two numbers and discarding the result.

• The teq mnemonic is functionally the same as performing the bitwise OR of


the two numbers and discarding the result.

• The tst and teq mnemonics are used to test the logical equivalence of an
entire register.
• A multi-bit value evaluates as “false” only if all bits are zero.
Comparisons and Conditional Execution
• Most of the time you can do most comparisons just by using cmp; the other
three variants (i.e. cmn, tst, teq) are more specialized.
• Note that the condition codes in the previous table (i.e. Table A) are only valid
for the cmp operation.
• The Status Flags Checked is always appropriate—the condition codes always
perform the same checks on the status flags to determine whether or not
code should execute—but the meaning is different.
Updating Condition Flags
Instruction Operands Brief description Flags
CMP Rn, Op2 Compare N,Z,C,V
CMN Rn, Op2 Compare Negative N,Z,C,V
TEQ Rn, Op2 Test Equivalence N,Z,C
TST Rn, Op2 Test N,Z,C
➢ Update the status flags
• No need to add S.
• No need to specify destination register.
➢ Operations are:
• CMP operand1 - operand2, but result not written
• CMN operand1 + operand2, but result not written
• TEQ operand1 ^ operand2, but result not written
• TST operand1 & operand2, but result not written

Examples:
• CMP r0, r1
• TST r2, #5
Comparisons and Conditional Execution
Example 34: Describe the following code
ldr r0 , =0x88AABEEF
mov r1 , r0
@ compare r0 with r1
cmp r0 , r1 @ calculate r0-r1 , discard answer, update N,Z,C,V flags
moveq r2 , #5 @ execute if r0 = r1 (compand executes)

@ compare r0 with negative value of r1


cmn r0 , r1 @ calculate r0+r1 , discard answer, update N,Z,C,V flags
moveq r2 , #3 @ execute if r0 = -r1 (Compand does not execute since Z=0)

@ performs a bitwise AND operation and discards result


tst r0 , r1 @ updates N and Z flags; does not affect V flag
movgt r3 , #4 @ gt status flag Z=0 and N=V, (should not use movgt)
Comparisons and Conditional Execution

Table A: List of conditional execution codes, which will be true when the condition for two
numbers x and y given in the description is valid. Many conditionals have different codes
depending on whether the test is with signed or unsigned numbers.
Bitwise Operations
• There are a variety of bitwise operations that can be performed on a value in
a register, such as the logical AND and OR operations.

• To compute the bitwise and of two numbers, use the mnemonic and.
• This requires at least two, and optionally three operands, the first of which
must be a register.
• The use of these three operands is the same as for add and sub.

• To compute the bitwise or of two numbers, use the mnemonic orr.


• This requires at least two, and optionally three operands, the first of which
must be a register.
• The use of these three operands is the same as for and.
Bitwise Operations
• The ARM-type microprocessors have a special piece of hardware called a
barrel shifter.
• The barrel shifter is very fast piece of hardware for rearranging the bits in a
binary sequence.
• It is implemented in assembly during a regular mnemonic code, and these
operations can be performed to the second operand in a mnemonic.
• Some of these bitwise operations are listed
in Table

• The difference between logical and arithmetic


shifts is whether the most significant bit
(MSB) is preserved as a “sign bit”.
Bitwise Operations
• Each of these operations is followed by a number,
indicating the number of bits for the operation.
• Logical fill in the missing bits with zeros, while
rotate wraps around.
• Arithmetic shifts preserve the most significant bit of the number, in case that
is a sign flag.
Barrel Shifter
Logical Shift Left (LSL) Arithmetic Shift Right (ASR)

Logical Shift Right (LSR) Rotate Right (ROR)

Rotate Right Extended (RRX)


Why is there rotate right but no
rotate left?
Rotate left can be replaced by a rotate
right with a different rotate offset.
Can rotate data only one bit
Bitwise Operations
Example 35: A microprocessor has 8 bit registers. if
r0 = 0b0110 0111 and r2 = 0b10010101. What do
the following commands do?

mov r1, r0, lsl #3


mov r1, r2, lsr #3
asr r1, r2, #3
ror r1, r2, #5
rrx r1, r2,
Updating APSR Flags
• If “S” is present, the instruction update flags. Otherwise, the flags are not updated.
• Let R be the final 32-bit result

N Z C V
R<31> IsZeroBit(R) carry unchanged

LSLS
ASRS

LSRS

RORS
RRXS
Bitwise Operations
• These bitwise operations are sometimes used to simplify math, since shifting
all the bits left or right is a much quicker way to multiply or divide by 2 than
using the ALU.
• Another, possibly more common use for these operations is when the 32-bit
ARM registers need to communicate with peripherals that have larger or
smaller memory cell sizes.
• For example, if we read data into r1 and r2 as 16-bit numbers (i.e., in the 32-
bit registers, the most-significant 16 bits are zeros), we want to combine
these into one 32-bit number as:
add r1 , r2 , lsl #16 @ This puts the contents of r2 as the
@ most-significant 16 bits of r1.
Example 36 with Bitwise Operations
• The Terasic DE1-SoC has a set of 10 switches and a bank of 10 LEDs.
We will write a program to do the following:
• Read in the state of the switches, and represent the first 5 switches as
one binary number (read left-to-right), and the last 5 switches as a
second binary number (again, read left-to-right).
• Add these two numbers together.
• Subtract the result from the magic number, 789.
• Output the result to the LED bank.

• One way to implement this is shown in the next slide


Example with Bitwise Operations
.global _start @Note the use of directives to define data values (.data, where
.data @magic_num is defined) and the main code (.text).
magic_num: .word 789 @define the magic number
.text
_start:
ldr r3 , adr_magic @load addresses for magic number
ldr r4 , adr_led @and i/o hardware
ldr r5 , adr_switch
ldr r1 , [r5] @read in state of the switches
mov r2 , r1 , lsr #5 @move the 5-MSbs into register r2
and r1 , #31 @mask the 5-MSbs from original note that 31 = 0b11111
add r1 , r2 @add and overwrite
ldr r2 , [r3] @get magic number
sub r2 , r1 @subtract and overwrite
str r2 , [r4] @write to LED bank
adr_magic: .word magic_num @Note also the use of labels at the end of the code to identify
adr_led: .word 0xff200000 @addresses.
adr_switch: .word 0xff200040
Example with Bitwise Operations
• Like all memory-mapped peripherals, the addresses
.global _start
.data
for the LEDs and switches are provided
magic_num: .word 789
.text
_start: • Technically it is not necessary to define a label for
ldr r3 , adr_magic these addresses, they could be loaded directly into
ldr r4 , adr_led
ldr r5 , adr_switch
registers (as ldr r3, =0xff200000).
ldr r1 , [r5]
mov r2 , r1 , lsr #5 • It is useful to use a label for the address of the magic
and r1 , #31 number. The data block creates the magic number in
add r1 , r2
ldr r2 , [r3] memory, but we don’t know where in memory—that
sub r2 , r1 is determined by the compiler.
str r2 , [r4]
adr_magic: .word magic_num
adr_led: .word 0xff200000
adr_switch: .word 0xff200040
Which is Greater: 0xFFFFFFFF or 0x00000001?
Example 37: Convert C code to assembly
It’s software’s responsibility to tell computer how to interpret data:
• If written in C, declare the signed vs unsigned variable
• If written in Assembly, use signed vs unsigned branch instructions
signed int x, y ; MOVS r5, #0xFFFFFFFF
x = -1; MOVS r6, #0x00000001
y = 1; CMP r5, r6
if (x > y) BLE Then_Clause
... ...
BLE: Branch if less than or equal, signed ≤
unsigned int x, y ; MOVS r5, #0xFFFFFFFF
x = 4294967295; MOVS r6, #0x00000001
y = 1; CMP r5, r6
if (x > y) BLS Then_Clause
... ...
BLS: Branch if lower or same, unsigned ≤
Comparisons and Conditional Execution

Table A: List of conditional execution codes, which will be true when the condition for two
numbers x and y given in the description is valid. Many conditionals have different codes
depending on whether the test is with signed or unsigned numbers.
Branching
• As previously discussed, the program counter (register pc) keeps track of the
next instruction in memory.
• Under normal circumstances the program counter automatically increments by
4 after each instruction is completed, so the program is read out sequentially
from memory.
• Note that for conditional execution, the instruction is still read sequentially, it
just may not be executed depending on the present condition.
• For a fully functional programming language, sequential execution is not
sufficient: there must be a way to branch to non-sequential regions of code.
• Since the pc acts as a register, one way to branch is to add or subtract values
from the pc. However, this is an extreme solution and there are better
approaches.
Branching
• The preferred way to create branches in your program is to use the equivalent
of a GOTO command to jump to a label somewhere else in your code.

• To perform a direct branch to a known location in your program, use the b


mnemonic. This requires a single label as an operand.

• To perform an indirect branch to a variable location in your program, use the


bx mnemonic. This requires a single register as an operand, the register
should hold the memory address of appropriate instruction.

• Like every mnemonic, both b and bx can have appended conditional codes.
Branching
Example 38: Describe the following codes
mov r0 , #8 @ initialize r0
cmp r0 , #5 @ compare
strlo r0 , [r1] @ store to memory if r0 < 5 (not performed)
• Implementing the same code using a branch:
mov r0 , #8 @ initialize r0
cmp r0 , #5 @ compare
bhi more_code @ skip next line if r0 > 5
str r0 , [r1] @ not performed
more_code:
• The code puts the conditional on the branch mnemonic bhi, so the str
instruction is completely skipped if 8 > 5.
Branching
mov r0 , #8 @ initialize r0
cmp r0 , #5 @is r0 < 5?
bhi more_code @ skip next line if r0 < 5
str r0 , [r1]
more_code:

• In this example, using a branch is probably a worse idea than just using a
conditional execution of str.

• However, if there were multiple lines of code that were conditional, using
one branch mnemonic to skip over then entire block rather than write each
instruction as a conditional execution may be better.
Branching
Implementing the same code using indirect branches
mov r0 , #8 • the program counter is stored in r2 and then
mov r2 , pc increased by 12, as the line after the
add r2 , #12 more_code label is four lines ahead of the point
cmp r0 , #5 where pc is stored in r2. Here pc is incremented
bxhi r2 by 4 before it is written to r2, and 16 = 12 + 4
str r0 , [r1]
more_code:
If... Then... Else
• Most programming languages have an if...then...else conditional structure.
• This can be implemented without branches, just by having the appropriate
conditionals and counter-conditionals on the then and else statements.

Example 39: Implementing if else statements (without branching)


mov r0 , #8
cmp r0 , #5 @ compare
addls r1 , r2 @ add if #8 ≤ #5 due to ls
subls r0 , #1 @ sub if #8 ≤ #5 due to ls
addhi r1 , r3 @ add if #8 > #5 due to hi
@ add if #8 > #5 due to hi
addhi r0 , #1
Comparisons and Conditional Execution

Table A: List of conditional execution codes, which will be true when the condition for two
numbers x and y given in the description is valid. Many conditionals have different codes
depending on whether the test is with signed or unsigned numbers.
If... Then... Else
• Adding conditional codes makes the mnemonics longer and arguably harder
to read. If there is only one or few lines of code for each condition, then it is
probably appropriate.
• However, your conditional requires several lines of code for the then and/or
else block, using a branch to avoid one or the other can make the code
simpler to read.
• Without using branches, you are also unable to update the status flags
inside an if...then...else block—so you can’t have any nested conditionals.
Using branches fixes this problem.

• Implementing the previous code using branching


If... Then... Else
Example 40: Implementing if else statements (with branching)
mov r0 , #8
if: cmp r0 , #5 @ compare
bhi else @ if #8 > #5 branch to else label (due to hi)
then: add r1 , r2 @ perform same commands as previous code
sub r0 , #1 @ perform same commands as previous code
b endif @ branch to endif label
else: add r1 , r3 @ perform same commands as previous code
add r0 , #1 @ perform same commands as previous code
b endif @ branch to endif label
… @ other code
endif: str r1 , [r4] @ endif label
Creating Loops
• Creating loops is an important functionality for a programming language, and
this can be implemented using conditional branching.
• There is no explicit for...next or do...while loops in assembly as there might be
in other programming languages, but the same functionality can be obtained
by using conditional branches in the correct place.
Example 41: Code that implements a for loop that iterates 10 times.
mov r4 , #10 @ initialize counter
loop: cmp r4 , #0 @ compare used to exit loop when counter=0
beq endloop @ if r4 = #0 branch endloop
…/*a whole bunch of code here */
sub r4 , #1 @ decrement counter
b loop @ branch back to start
endloop: /* rest of code here */
Creating Loops
• It is also worth noting that many microcontrollers are designed to run in
perpetuity: unless shut down manually by the user they should repeat their
programming.
• It is typically good practice to have the entire main program in an endless
loop. Once the end of the code is reached, the last line should be b _start
or something similar.
• It may also be necessary to loop almost endlessly while waiting for user input.

• The following example demonstrates a loop that waits unit one of the
switches on the DE1-SoC development board is thrown.
Creating Loops
Example 42: Code that waits unit one of the switches on the DE1-SoC
development board is switched.

ldr r4 , =0xff200040 @ memory address for switches


ldr r0 , [r4] @ get initial state
/* some code here */
pause_for_input:
ldr r1 , [r4] @ read switches
cmp r1 , r0 @ compare if switches changed
beq pause_for_input @ if r1 equals r2 branch to pause_for_input
mov r0 , r1 @new "old state " of switches
/* rest of code */
Creating Loops
ldr r4 , =0xff200040
ldr r0 , [r4] • When using the simulator and stepping through
/* some code here */ the code line by line, there is plenty of time to
pause_for_input: toggle switches.
ldr r1 , [r4] • However, the ARM®Cortex-A9 operates at clock
cmp r1 , r0 speeds of at least 800MHz
beq pause_for_input • Millions of processor cycles will have passed
mov r0 , r1 before your fingers manage to touch one of
/* rest of code */ the switches.
More Examples
Example 42: Covert the C code to assembly. a) //a is signed integer
if(a<0){
a=0–a;
}
x=x+1;

b) // x is a signed integer c) if (a==1 || a==7 || a==11)


y = 1;
if(x <= 20 || x >= 25){
else
a=1
y = -1;
}
More Examples
Example 43: Describe how the NZCV flags are updated

LDR r0, =0xFFFFFFFF


LDR r1, =0x00000001
ADDS r3, r0, r1

Solution to example 43
N(Negative) = 0
Z(Zero) = 1
C(Carry) = 1
V(oVerflow) = 0
More Examples
Example 44: Describe how the NZCV flags are updated
LDR r0, =0xFFFFFF00
LDR r1, =0x00000001
ADDS r2, r1, r0, LSL #1

Solution to example 44
N = 0, Z = 1, C = 1, V = 0

R2 =0xFFFFFE01
More Examples
Example 45: The following commands set the kth bit to one in the C
programming language and all other bits in a stay the same. Write the
equivalent code in assembly?
a |= (1 << k)
or
a = a | (1 << k)

Solution to example 45 for a |= (1 << 5)


Solution 1:
MOVS r4, #1 ; r4 = 1
LSLS r4, r4, #5 ; r4 = 1<<5
ORRS r0, r0, r4 ; r0 = r0 | 1<<5

Solution 2:
MOVS r4, #1 ; r4 = 1
ORRS r0, r0, r4, LSL #5 ; r0 = r0 | 1<<5
Example 46: The following commands clears the kth bit to zero in the C
programming language and all other bits in a stay the same. Write the
equivalent code in assembly? a &= ~(1<<k)

Solution to example 46 for a &= ~(1<<5)


Solution 1:
MOVS r4, #1 ; r4 = 1
LSLS r4, r4, #5 ; r4 = 1<<5
MVNS r4, r4 ; r4 = not (1<<5)
ANDS r0, r0, r4 ; r0 = r0 & not (1<<5)

Solution 2:
MOVS r4, #1 ; r4 = 1
MVNS r4, r4, LSL #5 ; r4 = not (1<<5)
ANDS r0, r0, r4 ; r0 = r0 & not (1<<5)

Solution 3:
MOVS r4, #1 ; r4 = 1
BICS r0, r0, r4, LSL #5 ; r0 = r0 | 1<<5
Example 47: The following commands complements the kth bit in the C
programming language and all other bits in a stay the same. Write the
equivalent code in assembly?
a ^= 1<<k
Solution to example 47 for a ^= 1<<5
Solution:
MOVS r4, #1 ; r4 = 1
EORS r0, r0, r4, LSL #5 ; r0 = r0 ^ 1<<5
More Examples
Example 48: An ARM®Cortex-A9 the initial contents in
registers and memory are provided. The following code is
executed. After the code is complete, what are the
contents of the registers and memory?
ldr r1 , [r0], #4
ldr r2 , [r0 ,#4]
ldr r3 , [r0 ,#4 ]!
ldr r4 , [r0 ,#4 ]!
str r3 , [r0 , #-8 ]!
cmp r2 , r4
strge r2 , [r0 ,#8]
adds r1 , r3 , lsl #2
strhi r1 , [r0 ,#4 ]!
str r4 , [r0]
Solution to example 48

• Contents of registers and


memory cells after code
is executed.
Assembly Language
Example 49: Assuming that all registers are initialized to 0x00000000 at the start
of the following code, identify the register contents and the status flags after
each line.
mov r0 , #1
movs r1 , r0 , lsl #31
lsls r1 , #1
movs r1 , r0 , lsl #30
adds r1 , r1
lsls r1 , #1
subs r2 , r0 , r0
movs r0 , #10
adds r2 , r3
subs r2 , r0
adds r2 , r0 , lsl #30
Assembly Language
Solution to example 49

You might also like