ARM Assembly Language Programming (part 3)

3. The Instruction Set

We now know what the ARM provides by way of memory and registers, and the sort of instructions to manipulate them.This chapter describes those instructions in great detail.

As explained in the previous chapter, all ARM instructions are 32 bits long. Here is a typical one:

10101011100101010010100111101011

Fortunately, we don't have to write ARM programs using such codes. Instead we use assembly language. We saw at the end of Chapter One a few typical ARM mnemonics. Usually, mnemonics are followed by one or more operands which are used to completely describe the instruction.

An example mnemonic is ADD, for 'add two registers'. This alone doesn't tell the assembler which registers to add and where to put the result. If the left and right hand side of the addition are R1 and R2 respectively, and the result is to go in R0, the operand part would be written R0,R1,R2. Thus the complete add instruction, in assembler format, would be:

ADD R0, R1, R2 ;R0 = R1 + R2

Most ARM mnemonics consist of three letters, e.g. SUBMOVSTRSTM. Certain 'optional extras' may be added to slightly alter the affect of the instruction, leading to mnemonics such as ADCNES and SWINE.

The mnemonics and operand formats for all of the ARM's instructions are described in detail in the sections below. At this stage, we don't explain how to create programs, assemble and run them. There are two main ways of assembling ARM programs - using the assembler built-in to BBC BASIC, or using a dedicated assembler. The former method is more convenient for testing short programs, the latter for developing large scale projects. Chapter Four covers the use of the BASIC assembler.

3.1 Condition codes

The property of conditional execution is common to all ARM instructions, so its representation in assembler is described before the syntax of the actual instructions.

As mentioned in chapter two, there are four bits of condition encoded into an instruction word. This allows sixteen possible conditions. If the condition for the current instruction is true, the execution goes ahead. If the condition does not hold, the instruction is ignored and the next one executed.

The result flags are altered mainly by the data manipulation instructions. These instructions only affect the flags if you explicitly tell them to. For example, a MOV instruction which copies the contents of one register to another. No flags are affected. However, the MOVS (move with Set) instruction additionally causes the result flags to be set. The way in which each instruction affects the flags is described below.

To make an instruction conditional, a two-letter suffix is added to the mnemonic. The suffixes, and their meanings, are listed below.

AL Always

An instruction with this suffix is always executed. To save having to type 'AL' after the majority of instructions which are unconditional, the suffix may be omitted in this case. Thus ADDAL and ADD mean the same thing: add unconditionally.

NV Never

All ARM conditions also have their inverse, so this is the inverse of always. Any instruction with this condition will be ignored. Such instructions might be used for 'padding' or perhaps to use up a (very) small amount of time in a program.

EQ Equal

This condition is true if the result flag Z (zero) is set. This might arise after a compare instruction where the operands were equal, or in any data instruction which received a zero result into the destination.

NE Not equal

This is clearly the opposite of EQ, and is true if the Z flag is cleared. If Z is set, and instruction with the NE condition will not be executed.

VS Overflow set

This condition is true if the result flag V (overflow) is set. Add, subtract and compare instructions affect the V flag.

VC Overflow clear

The opposite to VS.

MI Minus

Instructions with this condition only execute if the N (negative) flag is set. Such a condition would occur when the last data operation gave a result which was negative. That is, the N flag reflects the state of bit 31 of the result. (All data operations work on 32-bit numbers.)

PL Plus

This is the opposite to the MI condition and instructions with the PL condition will only execute if the N flag is cleared.

The next four conditions are often used after comparisons of two unsigned numbers. If the numbers being compared are n1 and n2, the conditions are n1>=n2, n1<n2, n1>n2 and n1<=n2, in the order presented.

CS Carry set

This condition is true if the result flag C (carry) is set. The carry flag is affected by arithmetic instructions such as ADDSUB and CMP. It is also altered by operations involving the shifting or rotation of operands (data manipulation instructions).

When used after a compare instruction, CS may be interpreted as 'higher or same', where the operands are treated as unsigned 32-bit numbers. For example, if the left hand operand of CMP was 5 and the right hand operand was 2, the carry would be set. You can use HS instead of CS for this condition.

CC Carry clear

This is the inverse condition to CS. After a compare, the CC condition may be interpreted as meaning 'lower than', where the operands are again treated as unsigned numbers. An synonym for CC is LO.

HI Higher

This condition is true if the C flag is set and the Z flag is false. After a compare or subtract, this combination may be interpreted as the left hand operand being greater than the right hand one, where the operands are treated as unsigned.

LS Lower or same

This condition is true if the C flag is cleared or the Z flag is set. After a compare or subtract, this combination may be interpreted as the left hand operand being less than or equal to the right hand one, where the operands are treated as unsigned.

The next four conditions have similar interpretations to the previous four, but are used when signed numbers have been compared. The difference is that they take into account the state of the V (overflow) flag, whereas the unsigned ones don't.

Again, the relationships between the two numbers which would cause the condition to be true are n1>=n2, n1<n2, n1>n2, n1<=n2.

GE Greater than or equal

This is true if N is cleared and V is cleared, or N is set and V is set.

LT Less than

This is the opposite to GE and instructions with this condition are executed if N is set and V is cleared, or N is cleared and V is set.

GT Greater than

This is the same as GE, with the addition that the Z flag must be cleared too.

LE Less than or equal

This is the same as LT, and is also true whenever the Z flag is set.

Note that although the conditions refer to signed and unsigned numbers, the operations on the numbers are identical regardless of the type. The only things that change are the flags used to determine whether instructions are to be obeyed or not.

The flags may be set and cleared explicitly by performing operations directly on R15, where they are stored.

3.2 Group one - data manipulation

This group contains the instructions which do most of the manipulation of data in ARM programs. The other groups are concerned with moving data between the processor and memory, or changing the flow of control.

The group comprises sixteen distinct instructions. All have a very similar format with respect to the operands they take and the 'optional extras'. We shall describe them generically using ADD, then give the detailed operation of each type.

Assembler format

ADD has the following format:

ADD{cond}{S} <dest>, <lhs>, <rhs>

The parts in curly brackets are optional. Cond is one of the two-letter condition codes listed above. If it is omitted, the 'always' condition AL is assumed. The S, if present, causes the instruction to affect the result flags. If there is no S, none of the flags will be changed. For example, if an instruction ADDS É yields a result which is negative, then the N flag will be set. However, just ADD É will not alter N (or any other flag) regardless of the result.

After the mnemonic are the three operands. <dest> is the destination, and is the register number where the result of the ADD is to be stored. Although the assembler is happy with actual numbers here, e.g. 0 for R0, it recognises R0, R1, R2 etc. to stand for the register numbers. In addition, you can define a name for a register and use that instead. For example, in BBC BASIC you could say:-

iac = 0

where iac stands for, say, integer accumulator. Then this can be used in an instruction:-

ADD iac, iac, #1

The second operand is the left hand side of the operation. In general, the group one instructions act on two values to provide the result. These are referred to as the left and right hand sides, implying that the operation determined by the mnemonic would be written between them in mathematics. For example, the instruction:

ADD R0, R1, R2

has R1 and R2 as its left and right hand sides, and R0 as the result. This is analogous to an assignment such as R0=R1+R2 in BASIC, so the operands are sometimes said to be in 'assignment order'.

The <lhs> operand is always a register number, like the destination. The <rhs> may either be a register, or an immediate operand, or a shifted or rotated register. It is the versatile form that the right hand side may take which gives much of the power to these instructions.

If the <rhs> is a simple register number, we obtain instructions such as the first ADD example above. In this case, the contents of R1 and R2 are added (as signed, 32-bit numbers) and the result stored in R0. As there is no condition after the instruction, the ADD instruction will always be executed. Also, because there was no S, the result flags would not be affected.

The three examples below all perform the same ADD operation (if the condition is true):

ADDNE R0, R0, R2
ADDS R0, R0, R2
ADDNES R0, R0, R2

They all add R2 to R0. The first has a NE condition, so the instruction will only be executed if the Z flag is cleared. If Z is set when the instruction is encountered, it is ignored. The second one is unconditional, but has the S option. Thus the N, Z, V and C flags will be altered to reflect the result. The last example has the condition and the S, so if Z is cleared, the ADD will occur and the flags set accordingly. If Z is set, the ADD will be skipped and the flags remain unaltered.

Immediate operands

Immediate operands are written as a # followed by a number. For example, to increment R0, we would use:

ADD R0, R0, #1

Now, as we know, an ARM instruction has 32 bits in which to encode the instruction type, condition, operands etc. In group one instructions there are twelve bits available to encode immediate operands. Twelve bits of binary can represent numbers in the range 0..4095, or -2048..+2047 if we treat them as signed.

The designers of the ARM decided not to use the 12 bits available to them for immediate operands in the obvious way just mentioned. Remember that some of the status bits are stored in bits 26..31 of R15. If we wanted to store an immediate value there using a group one instruction, there's no way we could using the straightforward twelve-bit number approach.

To get around this and related problems, the immediate operand is split into two fields, called the position (the top four bits) and the value (stored in the lower eight bits). The value is an eight bit number representing 256 possible combinations. The position is a four bit field which determines where in the 32-bit word the value lies. Below is a diagram showing how the sixteen values of the position determine where the value goes. The bits of the value part are shown as 0, 1, 2 etc.

The way of describing this succinctly is to say that the value is rotated by 2*position bits to the right within the 32-bit word. As you can see from the diagram, when position=&03, all of the status bits in R15 can be reached.

b31

b0

Pos

........................76543210

&00

10........................765432

&01

3210........................7654

&02

543210........................76

&02

76543210........................

&04

..76543210......................

&05

....76543210....................

&06

......76543210..................

&07

........76543210................

&08

..........76543210..............

&09

............76543210............

&0A

..............76543210..........

&0B

................76543210........

&0C

..................76543210......

&0D

....................76543210....

&0E

......................76543210..

&0F

The sixteen immediate shift positions

When using immediate operands, you don't have to specify the number in terms of position and value. You just give the number you want, and the assembler tries to generate the appropriate twelve-bit field. If you specify a value which can't be generated, such as &101 (which would require a nine-bit value), an error is generated. The ADD instruction below adds 65536 (&1000) to R0:

ADD R0, R0, #&1000

To get this number, the assembler might use a position value of 8 and value of 1, though other combinations could also be used.

Shifted operands

If the <rhs> operand is a register, it may be manipulated in various ways before it is used in the instruction. The contents of the register aren't altered, just the value given to the ALU, as applied to this operation (unless the same register is also used as the result, of course).

The particular operations that may be performed on the <rhs> are various types of shifting and rotation. The number of bits by which the register is shifted or rotated may be given as an immediate number, or specified in yet another register.

Shifts and rotates are specified as left or right, logical or arithmetic. A left shift is one where the bits, as written on the page, are moved by one or more bits to the left, i.e. towards the more significant end. Zero-valued bits are shifted in at the right and the bits at the left are lost, except for the final bit to be shifted out, which is stored in the carry flag.

Left shifts by n bits effectively multiply the number by 2n, assuming that no significant bits are 'lost' at the top end.

A right shift is in the opposite direction, the bits moving from the more significant end to the lower end, or from left to right on the page. Again the bits shifted out are lost, except for the last one which is put into the carry. If the right shift is logical then zeros are shifted into the left end. In arithmetic shifts, a copy of bit 31 (i.e. the sign bit) is shifted in.

Right arithmetic shifts by n bits effectively divide the number by 2n, rounding towards minus infinity (like the BASIC INT function).

A rotate is like a shift except that the bits shifted in to the left (right) end are those which are coming out of the right (left) end.

Here are the types of shifts and rotates which may be used:

LSL #n Logical shift left immediate

n is the number of bit positions by which the value is shifted. It has the value 0..31. An LSL by one bit may be pictured as below:

After n shifts, n zero bits have been shifted in on the right and the carry is set to bit 32-n of the original word.

Note that if there is no shift specified after the <rhs> register value, LSLÊ#0 is used, which has no effect at all.

ASL #n Arithmetic shift left immediate

This is a synonym for LSL #n and has an identical effect.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
This book is intended to be used in a first course in assembly language programming for Computer Science (CS) and Computer Engineering (CE) students. It is assumed that students using this book have already taken courses in programming and data structures, and are competent programmers in at least one high-level language. Many of the code examples in the book are written in C, with an assembly implementation following. The assembly examples can stand on their own, but students who are familiar with C, C++, or Java should find the C examples helpful. Computer Science and Computer Engineering are very large fields. It is impossible to cover everything that a student may eventually need to know. There are a limited number of course hours available, so educators must strive to deliver degree programs that make a compromise between the number of concepts and skills that the students learn and the depth at which they learn those concepts and skills. Obviously, with these competing goals it is difficult to reach consensus on exactly what courses should be included in a CS or CE curriculum. Traditionally, assembly language courses have consisted of a mechanistic learning of a set of instructions, registers, and syntax. Partially because of this approach, over the years, assembly language courses have been marginalized in, or removed altogether from, many CS and CE curricula. The author feels that this is unfortunate, because a solid understanding of assembly language leads to better understanding of higher-level languages, compilers, interpreters, architecture, operating systems, and other important CS an CE concepts. One of the goals of this book is to make a course in assembly language more valuable by introducing methods (and a bit of theory) that are not covered in any other CS or CE courses, while using assembly language to implement the methods. In this way, the course in assembly language goes far beyond the traditional assembly language course, and can once again pl
ARM汇编语言编程和架构是与ARM处理器相关的编程语言和计算机体系结构。 ARM汇编语言编程是使用ARM指令集进行编程的过程。ARM指令集是一种低级的机器语言,通过编写汇编指令可以直接控制ARM处理器执行特定的操作,例如加载和存储数据、算术运算和逻辑运算等。通过使用ARM汇编语言,程序员可以更细致地控制CPU和内存,从而提高程序的效率和性能。 ARM架构是ARM处理器的体系结构设计。ARM处理器是一种廉价、低功耗、高性能的处理器,广泛应用于移动设备(如手机和平板电脑)和嵌入式系统(如智能家居和汽车电子)。ARM架构采用了精简指令集计算(RISC)的设计思想,具有优化的执行效率和资源利用率。ARM架构还支持多核处理器和向量处理器等高级特性,以满足不同应用场景的需求。 ARM汇编语言编程和架构具有以下特点和优势: 1. 简单易学:ARM汇编语言语法简洁,易于学习和理解。 2. 灵活高效:ARM指令集提供了丰富的操作指令,允许程序员更精细地控制处理器和内存。 3. 低功耗高性能:ARM处理器采用了先进的微架构设计,具有较低的功耗和优异的性能。 4. 平台广泛:ARM处理器广泛应用于各种设备和系统,提供了丰富的开发工具和生态系统支持。 总之,ARM汇编语言编程和架构是掌握和应用ARM处理器的关键知识,对于开发高效、低功耗的嵌入式系统和移动应用具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值