ARM Assembly Language Programming (part 4)

本文档介绍了如何在BBC BASIC中使用内置汇编器进行ARM汇编语言编程。通过示例展示了如何开始和退出汇编模式,设置位置计数器,以及如何编写和执行简单的ARM程序。此外,还探讨了宏、条件汇编和调用机器代码的技巧,强调了BBC BASIC汇编器的便利性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4. The BBC BASIC Assembler

There are two main ways of writing ARM assembly language programs. One is to use a dedicated assembler. Such a program takes a text file containing ARM assembly language instructions, assembles it, and produces another file containing the equivalent machine code. These two files are called the source files and object files respectively.

An alternative approach is to use the assembler built-in to BBC BASIC. The ability to mix assembler with BASIC is a very useful feature of the language, and one that is relatively straightforward to use. For this reason, and because of the widespread availability of BBC BASIC, we describe how to use its built-in assembler. The examples of the next two chapters are also in the format expected by the BASIC assembler.

4.1 First principles

Two special 'statements' are used to enter and exit from the assembler. The open square bracket character, [, marks the start of assembly language source. Whenever this character is encountered where BASIC expects to see a statement like PRINT or an assignment, BASIC stops executing the program and starts to assemble ARM instructions into machine code. The end of the source is marked by the close square bracket, ]. If this is read where BASIC is expecting to see an instruction to be assembled, it leaves assembler mode and starts executing the (BASIC) program again.

To see the effect of entering and leaving the assembler, type in this short program:

10 PRINT "Outside the assembler"
20 [ ;In the assembler
30 ]
40 PRINT "Outside the assembler"

If you RUN this, you should see something like the following:

Outside the assembler
00000000 ;In the assembler
Outside the assembler

Between the two lines produced by the PRINT statements is one which the assembler printed. Unless you tell it not to, the assembler prints an assembly listing. We shall describe this in detail, but for now suffice is to say that it consists of three parts: an address (the eight zeros above, which may be different whenyou run the program), the machine code instruction in hex, and the source instruction being assembled.

In our example above, no instructions were assembled, so no machine code was listed. The only line of source was a comment. The semi-colon, ;, introduces a line of comment to the assembler. This acts much as a REM in BASIC, and causes the text after it to be ignored. The comment was indented somewhat in the assembly listing, as the assembler leaves space for any machine code which might be produced.

The address printed at the start of the line is called the location counter. This tells us two things: where the assembler is placing assembled machine code instructions in memory, and what the value of the program counter (PC) will be when that instruction is fetched for execution, when the program finally comes to be run. Because we are not assembling any instructions, no code will be written to memory, so it doesn't matter what the location counter's value is. Normally, though, when you assemble code, you should set the location counter to some address where the assembler may store the machine code.

It is easy to set the location counter, as it is stored in the system integer variable P%. If you enter the immediate statement:

PRINT ~P%

you will see the same figures printed as at the start of the middle line above (except for leading zeros).

Let us now assemble some actual code. To do this, we need to reserve some storage for the object code. This is easily done using the form of DIM which reserves a given number of bytes. Type in the following:

10 DIM org 40
20 P% = org
30 [ ;A simple ARM program
40 MOV R0,#32
50.LOOP
60 SWI 0
70 ADD R0,R0,#1
80 CMP R0,#126
90 BNE LOOP
100 MOV R15,R14
110 ]

It may seem strange using the variable org in the DIM, then using it only once to set P%, but we shall see the reason for this later. Note that the DIM statement returns an address which is guaranteed to be aligned on a word boundary, so there is no need to 'force' it to be a multiple of four.

As in the previous example, the first line of the assembler is a comment. The next seven lines though are actual assembly language instructions. In fact, you may recognise the program as being very similar to the example given at the end of Chapter One. It is a simple loop, which prints the character set from ASCII 32 (space) to ASCII 126 (tilde or ~).

The lines which are indented by a space are ARM mnemonics, followed by their operands. When the assembler encounters these, it will convert the instruction into the appropriate four-byte machine code, and then store this at the current location counter - P%. Then P% will be increased by four for the next instruction.

Line 50, which starts with a ., is a label. A label is a variable which marks the current place in the program. When it encounters a label, the assembler stores the current value of the location counter into the variable, so that this place in the program may be accessed in a later instruction. In this case the BNE at line 90 uses the label LOOP to branch back to the SWI instruction. Any numeric variable may be used as a label, but by convention floating point variables (without % sign) are used. Every label in a program should have a unique name. This isn't hard to achieve as BBC BASIC allows very long names.

If you RUN the program, another assembly listing will be produced, this time looking like:

000167C8 ;A simple ARM program
000167C8 E3A00020 MOV R0,#32
000167CC .LOOP
000167CC EF000000 SWI 0
000167D0 E2800001 ADD R0,R0,#1
000167D4 E350007E CMP R0,#126
000167D8 1AFFFFFB BNE LOOP
000167DC E1A0F00E MOV R15,R14

The first column is the location counter, and in the listing above, we can see that the first machine instruction was placed at address &167C8. Next is the hex representation of that instruction, i.e. the code which will actually be fetched and executed by the processor. You can verify that this is what was stored by the assembler by typing in:

PRINT ~!&167C8

(The address should be whatever was printed when you ran the program.) You will see E3A00020, as in the listing.

In the third column is the label for that instruction, or spaces if there isn't one, followed by the rest of the line, as typed by you.

To see the fruits of you labours, type the command:

CALL org

The ASCII character set of the machine will be printed. The CALL statement takes the address of a machine code routine, which it then executes. The machine code is called as if a BL instruction had been used with the address given as the operand. Thus to return to BASIC, the return address in R14 is transferred to R15 (the PC) as in the example above.

We will have more to say about using CALL (and the associated function USR) later in this chapter.

4.2 Passes and assembly options

Frequently, a label is defined after the place (or places) in the program from which it is used. For example, a forward branch might have this form:

100 CMP R0,#10
110 BNE notTen
120 ; some instructions
130 ; ...
140.notTen

In this example, the label notTen has not been encountered when the instruction at line 110 is assembled. It is not defined until line 140. If this or a similar sequence of instructions were encountered while assembling a program using the method we have already described, a message of the type 'Unknown or missing variable' would be produced.

We clearly need to be able to assemble programs with forward references, and the BBC BASIC assembler adopts the same approach to the problem as many others: it makes two scans, or passes, over the program. The first one is to enable all the labels to be defined, and the second pass assembles the code proper.

In the BASIC assembler we tell it to suppress 'errors' during the first pass by using the OPT directive. A directive (or pseudo-op as they are also called) is an instruction which doesn't get converted into machine code, but instead instructs the assembler to perform some action. It is used in the same place as a proper instruction.

The OPT directive is followed by a number, and is usually placed immediately after the [, but can in fact be used anywhere in the source code. The number is interpreted as a three-bit value. Bit zero controls the assembly listing; bit one controls whether 'Unknown or missing variable' type errors are suppressed or not, and bit two controls something called offset assembly, which we shall come to later. The eight possible values may be summarised as below:

Value

Offset assembly

Errors given

Listing

0 No No No
1 No No Yes
2 No Yes No
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、付费专栏及课程。

余额充值