Файл: Introduction to Microcontrollers. Architecture, Programming, and Interfacing of the Motorola 68HC12 (G.J. Lipovski, 1999).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 14.06.2025

Просмотров: 1408

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

100

Chapter 4 Assembly Language Programming

ORG $800

K:DC . b "ALPHA", 0 ; a NULL-terminated character string for part (b).

OUTPUT:

Ds. b

10

; storage buffer for output characters for part (c).

OUTPTR:

DC . w

OUTPUT

; pointer to the above buffer

a. Data

PRINT:

LDX #K

; get address of string

NEXT: LDAA 1, X+

; get a character of string, move pointer

BEQ

END

; if it is NULL, exit

BSR

PUT

; otherwise print the character in A

BRA

NEXT

; repeat the loop

END:

SWI

; return to the debugger

b. Calling PUT

PUT:

PSHX

; save

LDX

OUTPTR

; get pointer to output string

STAA 1, X+

; save character, move pointer

STX

OUTPTR

; save pointer

RTS

; return

PULX

; restore

Figure 4.8. Print Program

programming effort. From now on, we will not write machine code, but we will write (ASCII) source code and use the assembler to generate the machine code.

The first three examples illustrate character string processing. The first example prints out a character string. The second transfers a character string from one location to another. The third compares two strings, returning 1 if they match. These examples are similar to PUT, STRCPY, and STRCMP subroutines used in C.

Figure 4.8b's program prints a string of characters using a subroutine PUT, like problem 3.15. Such strings often end in a NULL (0) character. The program reads characters from the string using LDAA 1, X+, and calls PUT to print the character in A. This also sets the condition code Z bit if the byte that was loaded was NULL, which terminates execution of the loop. An analogous program inputs data from a keyboard using the subroutine GET and fills a vector with the received characters until a carriage return is received. These programs can be generalized. Any subroutine that uses characters from a null-terminated character string can be used in place of PUT, and any subroutine that puts characters into a string can be used instead of GET.

PUT and GET are actually I/O procedures we show in §11.8, which require considerable understanding of I/O hardware. We don't want to pursue the actual PUT and GET subroutines quite yet. Instead, we replace the actual PUT and GET subroutines with a stub subroutine (Figure 4.8c). After stopping the computer, examine the string OUTPUT to see what would be output. Similarly, a stub subroutine can be used instead of GET, to "input" characters. The sequence of input characters is preloaded into a string.

Our second example (Figure 4.9) copies a null-terminated character string from one location to another. The original string is generated by the assembler and downloaded into memory, using Src DC . b. The program copies it to another part of memory at Dst Ds . b. Note that the NULL is also copied to the destination string.


104

Chapter 4 Assembly Language Programming

ORG

$800

JSR

PASSI

JSR

PASS2

SWI

Figure 4.15. Assembler Main Program

The first instruction, which will be stored in location 0, loads the contents of location 3. The left two bits, the opcode, are 00, and the address of location 3 is 000011, so the machine code is 03 in hexadecimal. The next instruction's opcode is 01 for add; its effective address is 000100. The last instruction's opcode is 10 for store; its effective address is 000101. The source code shown in Figure 4.13b includes directives to initialize location 3 to $12, location 4 to $34, and location 5 to 0.

The assembler is written as two subroutines called PASSI and PASS 2. This program segment illustrates the usefulness of subroutines for breaking up a large program into smaller subroutines that are easier to understand and easier to debug.

The data are defined by assembler directives, generally written at the beginning of the program. See Figure 4.16. They can be written just after the program segment shown in Figure 4.15. The first directive allocates a byte to hold the object pointer (which is the location counter). The second directive allocates and initializes the ASCII source code to be assembled. The next two lines allocate two eight-element vectors, which will store the machine code and symbol table.

LCNTR:

Ds. b

1

; index used to store object code, which is the location counter

SOURCE:

Dc.b "

LA",$d," AB",$d," S C",$d,"A D 12",$d,"B D 34",$d,"C D00",$d,0;

OBJECT:

Ds.b

8

; machine code

LABELS:

Ds. b

8

; symbol table

Figure 4.16. Assembler Directives

PASS 1:

CLR

LCNTR ; clear index to object code vector

LDX

#SOURCE ; begin source scan: x-> first letter in source string

LDY

#LABELS ; y-> first symbol

P11:

LDAB

1, x+ ; get the line's first character to B and move x to next character

BEQ

PI4

; exit when a null character is encountered

CMPB

#'

' ; if B is a space

BEQ

PI3

; get opcode by going to PI3

STAB

1, y+ ; move character to symbol table

MOVE

LCNTR, 1,y+ ; put label value into symbol table

P13:

LDAB

1, x+ ; load B with character, move pointer

CMPB

#$d

; compare to carriage return which ends a line

BNE

P13

; until one is found. Note that x-> next character after this.

INC

LCNTR ; increment location counter (we are processing the next line)

BRA

PI 1

; go to PI 1 to process the next line

P14:

RTS

Figure 4.17. Assembler Pass 1



4.6 Summary

107

*Get hexadecimal value

*entry: X->first character of hex number

*

exit:

A:value, X->nextcharacter after hex number

*

saved:

B,Y

*

GETHEX:

BSR

GH1

; convert ascii character to a nibble

LSLA

; move to high nibble

LSLA

LSLA

LSLA

PSHA

; save on stack

BSR

GH1

; convert ascii character to a nibble

ORAA

1, sp+ ; pop and combine

*

RTS

GH1:

LDAA

1, x+ ; get next symbol

CMPA

#'9 '

BLS

GH2

SUBA

#7

GH2 :

SUBA

#' 0 '

; subtract ascii 0

RTS

Figure 421.Convert ASCII Hex String to a Binary Number

The reader should observe that this subroutine, PASS2, is broken into subroutines GETOPCD, GETHEX, and FINLBL. Each of these subroutines is more easily understood and debugged than a long program PASS2 that doesn't use subroutines. Each subroutine corresponds to an easily understood operation, which is described in the subroutine's header. This renders the subroutine PASS2 much easier to comprehend.

The contents of the vector OBJECT will be downloaded into the target machine and executed there. The assembler permits the programmer the ability to think and code at a higher level, not worrying about the low-level encoding of the machine code.

The reader should observe the following points from the above example. First, the two-pass assembler will determine where the labels are in the first pass. Thus, labels that are lower in the source code than the instructions that use these labels will be known in the second pass when the instruction machine code is generated. Second, these subroutines further provide many examples of techniques used to convert ASCII to hexadecimal, used to search for matching characters, and used to insert data into a vector.

4.6 Summary

In this chapter, we learned that an assembler can help you write much larger programs than you would be able to write by hand coding in machine code. Not only are the mnemonics for the instructions converted into instruction opcode bytes, but also symbolic addresses are converted into memory addresses. However, every new powerful


PROBLEMS

111

13. Write a shortest assembly-language (source code) subroutine that concatenates one null-terminated string onto the end of another null-terminated string, storing a null at the end of the expanded string. Assume that on entry, X points to the first string, Y points to the second string, and there is enough space after the second string to fit the first string into this space. This program is essentially the C procedure strcat().

14. Write a shortest assembly-language (source code) subroutine to compare at most n characters of one null-terminated string to those of another null-terminated string, similar to Figure 4.10. Assume X points to the first string, and Y points to the second string, and A contains the number n. Return carry set if and only if the strings match.

15.Write a shortest assembly-language (source code) subroutine that builds a symbol table as in Figure 4.12a but stores six-letter symbolic names and a two-byte value in each symbol table row. Upon entry to the subroutine, X points to the first of the six letters (the other letters follow in consecutive locations), and accumulator D contains the two-byte value associated with this symbol. The symbol table is stored starting at label LABELS, and the number of symbols (rows) is stored in one-byte variable SIZE.

16.Write a shortest assembly-language (source code) subroutine that searches a symbol

table as in Figure 4.12b but searches six-letter symbolic names having a two-byte value in each symbol table row. Upon entry to the subroutine, X points to the first of the six letters (the other letters follow in consecutive locations). The symbol table is stored starting at label LABELS, and the number of symbols (rows) is stored in one-byte variable SIZE. The subroutine returns with carry bit set if and only if a matching symbol is found; then Y points to the beginning of the row where the symbol is found.

17 . Write a shortest assembly-language (source code) program that finds themaximum MAX of N 4-byte signed numbers contained in array Z where N < 100. Your program should have in it the assembler directives

N

DS

1

MAX

DS

4

Z

DS.L

100

and be position independent. How would your program change if the numbers were unsigned?

18. Write an assembly-language program that finds the sum SUM of two 4-byte signed magnitude numbers NUM1 and NUM2. The result should also be in signed-magnitude form. Your program should include the assembler directives

ORG

$800

N

DS

1

NUM1

DS

4

NUM2

DS

4

SUM

DS

4