At some point, you will begin using constants in your assembly, and they are
allowed in a handful of formats:
• Decimal, for example, 123
• Hexadecimal, for example, 0x3F
• n_xxx (Keil only) where: n is a base between 2 and 9 , xxx is a number in
that base.
Character constants consist of opening and closing single quotes,
String constants are contained within double quotes.
For example, in the Keil tools, you could say something like
MOV r3, #’A’ ; single character constant
GBLS str1 ; set the value of global string variable
str1 SETS “Hello world!\n”
In the Code Composer Studio tools, you might say
.string “Hello world!”
which places 8-bit characters in the string into a section of code, but the .string
directive neither adds a NUL character at the end of the characters nor
interprets escape characters. Instead, you could say
.cstring “Hello world!\n”
PREDEFINED REGISTER NAMES:
Most assemblers have a set of register names that can be used
interchangeably in your code, mostly to make it easier to read. The
ARM assembler is no different, and includes a set of predefined,
case-sensitive names that are synonymous with registers.
While the tools recognize predeclared names for basic registers,
status registers, floating-point registers, and coprocessors, only the
following are of immediate use to us:
r0-r15 or R0-R15
s0-s31 or S0-S31
a1-a4 (argument, result, or scratch registers, synonyms for r0 to r3)
sp or SP (stack pointer, r13)
lr or LR (Link Register, r14)
pc or PC (Program Counter, r15)
cpsr or CPSR (current program status register)
spsr or SPSR (saved program status register)
apsr or APSR (application program status register)
name RN expr
where name is the name to be assigned to the register. Obviously name cannot
be the same as any of the predefined names. The expr parameter takes on
values from 0 to 15. Mind that you do not assign two or more names to the
same register.
EXAMPLE
code:
coeff1 RN 8 ; coefficient 1
coeff2 RN 9 ; coefficient 2
dest RN 0 ; register 0 holds the pointer to
; destination matrix
The syntax for the EQU directive is:
name EQU expr{,type}
where name is the symbolic name to assign to the value, expr is a register-
relative address, a program-relative address, an absolute address, or a 32-bit
integer [Link] parameter type is optional and can be any one of
ARM
THUMB
CODE16
CODE32
DATA
EXAMPLE
SRAM_BASE EQU 0x04000000 ; assigns SRAM a base address
abc EQU 2 ; assigns the value 2 to the symbol abc
xyz EQU label+8 ; assigns the address (label+8)
; to the symbol xyz
fiq EQU 0x1C, CODE32 ; assigns the absolute address 0x1C to the symbol fiq,
;and marks it as code
Declaring an Entry Point: In the Keil tools, the ENTRY directive declares an entry
point to a program. The syntax is:
ENTRY
Your program must have at least one ENTRY point for a program; otherwise, a
warning is generated at link time. If you have a project with multiple source
files, not every source file will have an ENTRY directive, and any single source
file should only have one ENTRY directive. The assembler will generate an error
if more than one ENTRY exists in a single source file.
EXAMPLE
AREA ARMex, CODE, READONLY
ENTRY ; Entry point for the application
When writing programs that contain tables or data that must be configured
before the program begins, it is necessary to specify exactly what memory looks
like.
Strings, floating-point constants, and even addresses can be stored in
memory as data using various directives.
DCB: actually defines the initial runtime contents of memory. The syntax is
{label} DCB expr{,expr}…
where expr is either a numeric expression that evaluates to an integer in the
range −128 to 255, or a quoted string, where the characters of the string are
stored consecutively in memory.
Since the DCB directive affects memory at the byte level, you should use an
ALIGN directive afterward if any instructions follow to ensure that the
instruction is aligned correctly in memory.
EXAMPLE:
Unlike strings in C, ARM assembler strings are not null-terminated. You can
construct a null-terminated string using DCB as follows:
C_string DCB “C_string”,0
If this string started at address 0x4000 in memory, it would look like
ALIGN directive: It aligns the current location to a specified boundary by
padding with zeros. The syntax is
ALIGN {expr{,offset}}
where expr is a numeric expression evaluating to any power of two from 2^0 to
2^31, and offset can be any numeric expression. The current location is aligned
to the next address of the form
offset + n * expr
If expr is not specified, ALIGN sets the current location to the next word (four
byte) boundary.
EXAMPLE:
AREA OffsetExample, CODE
DCB 1 ; This example places the two
ALIGN 4,3 ; bytes in the first and fourth
DCB 1 ; bytes of the same word
AREA Example, CODE, READONLY
start LDR r6, = label1 ; code
MOV pc,lr
label1 DCB 1 ; pc now misaligned
ALIGN ; ensures that subroutine1 addresses
Subroutine1 MOV r5, #0x5 ; the following instruction.
SPACE:
The syntax is: {label} SPACE expr
where expr evaluates to the number of zeroed bytes to reserve. You may also
want to use the ALIGN directive after using a SPACE directive, to align any code
that follows.
EXAMPLE: AREA MyData, DATA, READWRITE
data1 SPACE 255 ; defines 255 bytes of zeroed storage
Ending a Source File:
This is the easiest of the directives—END simply tells the assembler you’re at
the end of a source file. The syntax for the Keil tools is,
END
When you terminate your source file, place the directive on a line by itself.
MACROS: Macro definitions allow a programmer to build definitions of functions
or operations once, and then call this operation by name throughout the code,
saving some writing time.
In fact, macros can be part of a process known as conditional assembly,
wherein parts of the source file may or may not be assembled based on certain
variables, such as the architecture version (or a variable that you specify
yourself).
Two directives are used to define a macro: MACRO and MEND. The syntax is:
MACRO
{$label} macroname{$cond} {$parameter{,$parameter}…}
; code
MEND
Where $label is a parameter that is substituted with a symbol given when the
macro is invoked. The symbol is usually a label. The macro name must not
begin with an instruction or directive name.
The parameter $cond is a special parameter designed to contain a condition
code; however, values other than valid condition codes are permitted.
The term $parameter is substituted when the macro is invoked.
Within the macro body, parameters such as $label, $parameter, or $cond can be
used in the same way as other variables. They are given new values each time
the macro is invoked. Parameters must begin with $ to distinguish them from
ordinary symbols. Any number of parameters can be used. The $label field is
optional, and the macro itself defines the locations of any labels
EXAMPLE : Suppose you have a sequence of instructions that appears multiple
times in your code—in this case, two ADD instructions followed by a
multiplication. You could define a small macro as follows:
MACRO ; macro definition:
; vara = 8 * (varb + varc + 6)
$Label_1 AddMul $vara, $varb, $varc
$Label_1
ADD $vara, $varb, $varc ; add two terms
ADD $vara, $vara, #6 ; add 6 to the sum
LSL $vara, $vara, #3 ; multiply by 8
MEND
In your source code file, you can then instantiate the macro as many times as
you like. You might call the sequence as,
CSet1 AddMul r0, r1, r2 ; invoke the macro
; the rest of your code
and the assembler makes the necessary substitutions, so that the assembly
listing actually reads as,
CSet1 ; invoke the macro
ADD r0, r1, r2
ADD r0, r0, #6
LSL r0, r0, #3 ; the rest of your code
ORR r1, r1, #1:SHL:3 ;
set CCREG[3]
Here, a 1 is shifted left three bits.
Assuming you like to call register r1 CCREG,
you have now set bit 3.
The advantage in writing it this way is that you are more likely to understand
that you wanted a one in a particular bit location, rather than simply using a
logical operation with a value such as 0x8.
You can even use these operators in the creation of constants, for example,
DCD (0x8321:SHL:4):OR:2
MOV r0, #((1:SHL:14):OR:(1:SHL:12))
MOV r0, #((1 <<14) | (1 <<12))
MOV r0, #0x5000
Unit – II
ARM Instruction Set: Introduction, ARM instruction set-Data processing
and branch instructions, Thumb instruction set: The Thumb bit in the
CPSR, The Thumb programmer model, Thumb branch instructions,
Thumb software interrupt instructions, Thumb data processing
instructions, Thumb breakpoint instruction, Thumb implementation, and
Thumb applications. Example programs
Text 1 (5.1 to 5.14,7.1,7.2,7.3,7.4,7.5,7.6,7.7,7.8,7.9)
2.1 Introduction:
ARM processors support six data types:
8-bit signed and unsigned bytes.
16-bit signed and unsigned half-words; these are aligned on 2-byte
boundaries.
32-bit signed and unsigned words; these are aligned on 4-byte
boundaries.
ARM instructions are all 32-bit words and must be word-aligned.
Thumb instructions are half-words and must be aligned on 2-byte
boundaries.
Internally all ARM operations are on 32-bit operands; the shorter
data types are
only supported by data transfer instructions. When a byte is loaded
from memory it is zero- or sign-extended to 32 bits and then
treated as a 32-bit value for internal processing.
There are two ways to store words in a byte-addressed memory, depending on
whether the least significant byte is stored at lower or higher address.
• The “little-endian” and “big-endian” terminology is derived from Gulliver’s
Travels.
• The application of the “big-endian” and “little-endian” terms to the two ways
to organize computer memory comes from “On Holy Wars and a Plea for Peace”
by Danny Cohen in the October 1981 issue of Computer.
3
ARM operating modes and register usage
5
6 of 42
Load-store architecture
• 3-address instructions
• Conditional execution of every instruction
• Possible to load/store multiple registers at once
• Possible to combine shift and ALU operations in
a single instruction.
Instructions are classified into,
• Data processing
• Data movement
• Flow control
MOV<cc><S> Rd, <operands>
MOVCS R0, R1 @ if carry is set
@ then R0:=R1
MOVS R0, #0 @ R0:=0
@ Z=1, N=0
@ C, V unaffected
When this instruction is executed the only change to the
system state is the value of the destination register (and,
optionally, the N, Z, C and V flags in the CPSR).
Arithmetic operations: The carry-in, when used, is the current
value of the C bit in the CPSR.
• ADD r0, r1, r2 ; r0:=r1+r2
• ADC r0, r1, r2 ; r0:=r1+r2+C
• SUB r0, r1, r2 ; r0:=r1-r2
• SBC r0, r1, r2 ; r0:=r1-r2+C-1
• RSB r0, r1, r2 ; r0:=r2-r1
• RSC r0, r1, r2 ; r0:=r2-r1+C-1
Bit-wise logical operations.
• AND r0, r1, r2 ; r0:=r1 and r2
• ORR r0, r1, r2 ; r0:=r1 or r2
• EOR r0, r1, r2 ; r0:=r1 xor r2
• BIC r0, r1, r2 ; Bit Clear r0:=r1 and not r2
Register movement operations.
MOV Rd, MOVCS R0, R1 @ if carry is set @ then R0:=R1
MOVS R0, #0 @ R0:=0 @ Z=1, N=0 @ C, V unaffected
• MOV r0, r2 ; r0:=r2
• MVN r0, r2 ; r0:= not r2
Comparison operations.
These instructions do not produce a result but just set the
condition code bits (N, Z, C and V) in the CPSR according to
the selected operation.
• CMP r1, r2 ; set cc on r1-r2
• CMN r1, r2 ; set cc on r1+r2
• TST r1, r2 ; set cc on r1 and r2
• TEQ r1, r2 ; set cc on r1 xor r2
Immediate operands.
An immediate value is preceded by ‘#’, which may be
specified in hexadecimal notation by putting ‘&’ after the
‘#’.
• ADD r3, r3, #1 ; r3:=r3+1
• AND r8, r7, #&ff ; r8:=r7[7:0]
Example:To form a scalar product of two vectors:
MOV r11, #20 initialize loop counter
MOV r10, #0 initialize total
LOOP LDR r0, [r8], #4 get first component..
LDR r1, [r9], #4 . .and second
MLA r10, r0, r1, r10 accumulate product
SUBS rll, r11, #1 decrement loop counter
BNE LOOP
Data transfer instructions move data between ARM
registers and memory. There are three basic forms
of data transfer instruction in the ARM instruction
set:
• Single register load and store instructions.
- Flexible
• Multiple register load and store instructions.
- Less flexible, but enable large quantities of
data to be transferred efficiently
• Single register swap instructions.
- Mainly to implement semaphores and seldom
used in user-level programs.
• Pre-indexed LDR r0, [r1, #4] ; r0:=mem32[r1+4]
• Auto-indexing LDR r0, [r1, #4]! ; r0:=mem32[r1+4]
; r1:=r1+4
• Post-indexed (auto)
LDR r0, [r1], #4 ; r0:=mem32[r1]
; r1:=r1+4
Example:
• COPY ADR r1, TABLE1
ADR r2, TABLE2
• LOOP LDR r0, [r1], #4
STR r0, [r2], #4
???
…..
• TABLE1 ……
• TABLE2 …..
Examples To expand an array of signed half-
words into an array of words:
ADR r1, ARRAYl ; half-word array start
ADR r2, ARRAY2 ; word array start
ADR r3, ENDARR1 ; ARRAYl end + 2
LOOP LDRSH r0, [r1], #2 ; get signed half-word
STR r0, [r2], #4 ; save word
CMP r1, r3 ; check for end of array
BLT LOOP ; if not finished, loop
Multiple register data transfer.
• LDMIA r1, {r0, r2, r5} ; r0:=mem32[r1]
; r2:=mem32[r1+4]
; r5:=mem32[r1+8]
Stack addressing.
- Full ascending:
- Empty ascending:
- Full descending:
- Empty descending:
Block copy addressing
- Increment before:
- Increment after:
- Decrement before:
- Decrement after:
Example: To save three work registers and the return address upon entering a
subroutine:
STMFD r13!, {r0-r2, r14}
LDMFD r13!, {r0-r2, pc}
;This assumes that r13 has been initialized for use as a stack pointer. ;To
restore the work registers and return:
Examples: An unconditional jump
Conditional subroutine call:
Assembler format: B{L}X {<cond>} Rm
BLX <target address>
These instructions are available on ARM chips which support the
Thumb (16-bit) instruction set, and are a mechanism for switching
the processor to execute Thumb instructions or for returning
symmetrically to ARM and Thumb calling routines
BLX is available only on ARM processors that support architecture
v5T.
An unusual feature of the ARM instruction set is that
every instruction is conditionally executed.
The condition field occupies the top four of the 32-bit
instruction field:
Each of the 16 values of the condition field causes the
instruction to be executed or skipped according to the
values of the N, Z, C and V flags in the CPSR.
An unusual ARM feature is that all instructions may
be conditional:
CMP r0, #5 // if (r0 != 5)
{
ADDNE r1, r1, r0 // r1 := r1 + r0 - r2
SUBNE r1, r1, r2
}
This removes the need for some short branches,
improving performance and code density.
Assembler format: SWI{<cond>} <24-bit immediate>
The software interrupt instruction is used for calls to the operating
system and is often called a “supervisor call”. It puts the processor
into supervisor mode and begins executing instructions from
address 0x08.
The processor actions are:
Save the address of the instruction after the SWI in r14_svc.
Save the CPSR in SPSR_svc
Enter supervisor mode and disable IRQs (but not FIQs) by setting
CPSR[4:0] to 10011 and CPSR[7] to 1
Set the PC to 0816 and begin executing the instruction there.
Program Status Register Instructions:
• Instructions to read/write from/to CPSR or SPSR
• Instructions: MRS, MSR
• Syntaxes:
MRS{<cond>} Rd,<CPSR|SPSR>
MSR{<cond>} <CPSR|SPSR>,Rm
MSR{<cond>} <CPSR|SPSR>_<fields>,Rm
MSR{<cond>} <CPSR|SPSR>_<fields>,#immediate
• Modifying CPSR, SPSR: Read, Modify and Write back technique
- Read CPSR/SPSR using MRS
- Modify relevant bits
- Transfer to CPSR/SPSR using MSR
•Note:
• In user mode all fields can be read, but flags alone can be
modified
Examples:
- Program to enable FIQ (executed in svc mode)
MRS r1,cpsr ; copies CPSR into r1
BIC r1,#0x40 ; clears B6, i.e. FIQ interrupt mask bit
MSR cpsr,r1 ; copies r1 into CPSR
- Program to change mode (from svc mode to fiq mode)
MRS r0,cpsr ; get CPSR into r0
BIC r0,r0,0x1F ; clear the mode bits, i.e. 5 LSB bits - B[4:0]
ORR r0,r0,0x11 ; set to FIQ mode
MSR cpsr,r0 ; write r0 into CPSR
Examples:
1. FIND THE LENGTH OF STRING:
2. SUPPRESS LEADING ZEROS IN A STRING:
3. COMPARE TWO COUNTED STRINGS FOR EQUALITY
4. HEX TO ASCII CODE CONVERSION:
5. BCD TO HEX CODE CONVERSION:
6. UNPACKED BCD TO HEX
7. 16 BIT BINARY TO ASCII 0’S AND 1’S
8. BUBBLE SORT:
9. INITIATE A SIMPLE STACK:
10. SUBROUTINE IMPLEMENTATION (PASSING A VARIABLE)
11. ADDITION OF TWO 64 BIT NUMBERS USING SUBROUTINE:
12. A SUBROUTINE TO FIND FACTORIAL OF A GIVEN NUMBER: