ARM Assembly Language Programming (part 5)

本文介绍了ARM汇编语言编程的基本原理,包括控制结构、流程控制、递归和参数传递。通过实例展示了如何将高级语言的编程技巧转换为汇编语言,强调了位置无关代码的重要性,以及使用堆栈进行参数传递的机制。
摘要由CSDN通过智能技术生成

5. Assembly Programming Principles

The previous chapters have covered the ARM instruction set, and using the ARM assembler. Now we are in a position to start programming properly. Since we are assuming you can program in BASIC, most of this chapter can be viewed as a conversion course. It illustrates with examples how the programming techniques that you use when writing in a high-level language translate into assembler.

5.1 Control structures

Some theory

A program is made up of instructions which implement the solution to a problem. Any such solution, or algorithm, may be expressed in terms of a few fundamental concepts. Two of the most important are program decomposition and flow of control.

The composition of a program relates to how it is split into smaller units which solve a particular part of the problem. When combined, these units, or sub-programs, form a solution to the problem as a whole. In high-level languages such as BASIC and Pascal, the procedure mechanism allows the practical decomposition of programs into smaller, more manageable units. Down at the assembly language level, subroutines perform the same function.

Flow of control in a program is the order in which the instructions are executed. The three important types of control structure that have been identified are: the sequence, iteration, and decision.

An instruction sequence is simply the act of executing instructions one after another in the order in which they appear in the program. On the ARM, this action is a consequence of the PC being incremented after each instruction, unless it is changed explicitly.

The second type of control flow is decision: the ability to execute a sequence of instructions only if a certain condition holds (e.g. IF...THEN...). Extensions of this are the ability to take two separate, mutually exclusive paths (IF...THEN...ELSE...), and a multi-way decision based on some value (ON...PROC...). All of these structures are available to the assembly language programmer, but he has to be more explicit about his intentions.

Iteration means looping. Executing the same set of instructions over and over again is one of the computer's fortes. High-level languages provide constructs such as REPEAT..UNTIL and FOR...NEXT to implement iteration. Again, in assembler you have to spell out the desired action a little more explicitly, using backward (perhaps conditional) branches.

Some practice

Having talked about program structures in a fairly abstract way, we now look at some concrete examples. Because we are assuming you have some knowledge of BASIC, or similar high-level language, the structures found therein will be used as a starting point. We will present faithful copies of IF...THEN...ELSE,FOR...NEXT etc. using ARM assembler. However, one of the advantages of using assembly language is its versatility; you shouldn't restrict yourself to slavishly mimicking the techniques you use in BASIC, if some other more appropriate method suggests itself.

Position-independence

Some of the examples below (for example the ON...PROC implementation using a branch table) may seem slightly more complex than necessary. In particular, addressing of data and routines is performed not by loading addresses into registers, but by performing a calculation (usually 'hidden' in an ADR directive) to obtain the same address. This seemingly needless complexity is due to a desire to make the programs position-independent.

Position-independent code has the property that it will execute correctly no matter where in memory it is loaded. In order to possess this property, the code must contain no references to absolute objects. That is, any internal data or routines accessed must be referenced with respect to some fixed point in the program. As the offset from the required location to the fixed point remains constant, the address of the object may be calculated regardless of where the program was loaded. Usually, addresses are calculated with respect to the current instruction. You would often see instructions of the form:

.here ADD ptr, pc, #object-(here+8)

to obtain the address of object in the register ptr. The +8 part occurs because the PC is always two instructions (8 bytes) further on than the instruction which is executing, due to pipelining.

It is because of the frequency with which this calculation crops up that the ADR directive is provided. As we explained in Chapter Four, the line above could be written:

ADR ptr, object

There is no need for a label: BASIC performs the calculation using the current value of P%.

Instead of using PC offsets, a program can also access its data using base-relative addressing. In this scheme, a register is chosen to store the base address of the program's data. It is initialised in some position-independent way at the start of the program, then all data accesses are relative to this. The ARM's register-offset address mode in LDR and STR make this quite a straightforward way of accessing data.

Why strive for position-independence? In a typical ARM system, the programs you write will be loaded into RAM, and may have to share that RAM with other programs. The operating system will find a suitable location for the program and load it there. As 'there' might be anywhere in the available memory range, your program can make no assumptions about the location of its internal routines and data. Thus all references must be relative to the PC. It is for this reason that branches use offsets instead of absolute addresses, and that the assembler provides the

LDR <dest>,<expression>

form of LDR and STR to automatically form PC-relative addresses.

Many microprocessors (especially the older, eight-bit ones) make it impossible to write position-independent code because of unsuitable instructions and architectures. The ARM makes it relatively easy, and you should take advantage of this.

Of course, there are bound to be some absolute references in the program. You may have to call external subroutines in the operating system. The usual way of doing this is to use a SWI, which implicitly calls absolute address &0000008. Pointers handed to the program by memory-allocation routines will be absolute, but as they are external to the program, this doesn't matter. The thing to avoid is absolute references to internal objects.

Sequences

These barely warrant a mention. As we have already implied, ARM instructions execute sequentially unless the processor is instructed to do otherwise. Sequence of high-level assignments:

LET a = b+c
LET d = b-c

would be implemented by a similar sequence of ARM instructions:

ADD ra, rb, rc
SUB rd, rb, rc

IF-type conditions

Consider the BASIC statement:

IF a=b THEN count=count+1

This maps quite well into the following ARM sequence:

CMP ra, rb
ADDEQ count, count, #1

In this and other examples, we will assume operands are in registers to avoid lots of LDRs and STRs. In practice, you may find a certain amount of processor-to-memory transfer has to be made.

The ARM's ability to execute any instruction conditionally enables us to make a straightforward conversion from BASIC. Similarly, a simple IF..THEN...ELSE such as this one

IF val<0 THEN sign=-1 ELSE sign=1

leads to the ARM equivalent:

TEQ val, #0
MVNMI sign, #0
MOVPL sign, #1

The opposite conditions (MI and PL) on the two instructions make them mutually exclusive (i.e. one and only one of them will be executed after the TEQ), corresponding to the same property in the THEN and ELSE parts of the BASIC statement.

There is usually a practical limit to how many instructions may be executed conditionally in one sequence. For example, one of the conditional instructions may itself affect the flags, so the original condition no longer holds. A multi-word ADD will need to affect the carry flag, so this operation couldn't be performed using conditional execution. The solution (and the only method that most processors can use) is to conditionally branch over unwanted instructions.

Below is an example of a two-word add which executes only if R0=R1:

CMP R0, R1
BNE noAdd
ADDS lo1, lo1, lo2
ADC hi1, hi1, hi2
.noAdd ...

Notice that the condition used in the branch is the opposite to that under which the ADD is to be performed. Here is the general translation of the BASIC statements:

IF cond THEN sequence1 ELSE sequence2 statement
;'ARM' version
;Obtain <cond>
B<NOT cond> seq2 ;If <cond> fails then jump to ELSE
sequence1 ;Otherwise do the THEN part
...
BAL endSeq2 ;Skip over the ELSE part
.seq2
sequence2 ;This gets executed if <cond> fails
...
.endSeq2
statement ;The paths re-join here

At the end of the THEN sequence is an unconditional branch to skip the ELSE part. The two paths rejoin at endSeq2.

It is informative to consider the relative timings of skipped instructions and conditionally executed ones. Suppose the conditional sequence consists of X group one instructions. The table below gives the timings in cycles for the cases when they are executed and not executed, using each method:

 

Branch

Conditional

Executed

s + Xs
2) Who uses ARM? Currently ARM CPU is licensed and produced by more than 100 companies and is the dominant CPU chip in both cell phones and tablets. Given its RISC architecture and powerful 32-bit instructions set, it can be used for both 8-bit and 32-bit embedded products. The ARM corp. has already defined the 64-bit instruction extension and for that reason many Laptop and Server manufactures are planning to introduce ARM-based Laptop and Servers. 3) Who will use our textbook? The primary audience of our textbook on ARM (ARM Assembly Language Programming & Architecture by Mazidi & Naimi) is undergraduate engineering students in Electrical and Computer Engineering departments. It can also be used by practicing engineers who need to move away from 8- and 16-bit legacy chips such as the 8051, AVR, PIC and HCS08/12 family of microcontrollers to ARM. Designers of the x86-based systems wanting to design ARM-based products can also benefit from this textbook. Table of Contents Chapter 1: The History of ARM and Microcontrollers Chapter 2: ARM Architecture and Assembly Language Programming Chapter 3: Arithmetic and Logic Instructions and Programs Chapter 4: Branch, Call, and Looping in ARM Chapter 5: Signed Numbers and IEEE 754 Floating Point Chapter 6: ARM Memory Map, Memory Access, and Stack Chapter 7: ARM Pipeline and CPU Evolution Appendix A: ARM Cortex-M3 Instruction Description Appendix B: ARM Assembler Directives Appendix C: Macros Appendix D: Flowcharts and Pseudocode Appendix E: Passing Arguments into Functions Appendix F: ASCII Codes
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值