Language of The Dragon - 6809 Assembler by Mike James
Language of The Dragon - 6809 Assembler by Mike James
Mike James
ISBN O 905104 35 6
Published by:
SIGMA TECHNICAL PRESS
5 Alton Road
Wilmslow
Cheshire
UK
Distributors:
Europe, Africa:
JOHN WILEY & SONS LIMITED
Baffins Lane, Chichester
West Sussex, England
Australia, New Zealand, South-East Asia:
Jacaranda-Wiley Ltd., Jacaranda Press,
JOHN WILEY & SONS INC.,
GPO Box 859, Brisbane,
Queensland 40001, Australia
ii
Preface
The6809 microprocessor that lies at the heart of the Dragon is one of the most
logical and easy-to-program of today's microprocessors. This makes it
particularly suitable for learning assembly language with the minimum of fuss
and confusion.
There are no short cuts to learning assembler and, unlike BASIC, where
you can start to write simple and useful programs when you've mastered only
iii
a few commands, there is a lot of ground to cover before you can do anything
that seems at all impressive. It IS worth the struggle however as, at the end of
the day, assembly language programming does bring all the promised
benefits of increased power and speed. Above all, assembly language
programming is a challenge which it is great fun to pursue.
iv
Contents
1. Why Assembler? 1
BASIC is easy 1
Which assembler? 2
Machine code and assembler 3
An assembler 4
Trial and error 6
3. Addressing 21
Operations and addresses 21
Direct addressing 22
Bits, bytes and binary 22
Hexadecimal and binary 24
Extended addressing 26
A practical program 27
Adding addressing modes to the BASIC assembler 30
Trying it out 33
Immediate addressing 34
Summary 35
Micro projects 36
v
4. Jumps, Loops and Labels 37
TheJMPinstruction 37
Address labels 40
Adding labels to the BASIC assembler 41
Forward jumps and two-pass assembly 43
Changing the BASIC assembler into a two-pass assembler 44
Subroutines, JSR and RTS 47
Using subroutines- more labels 47
Adding EQU to the BASIC assembler 49
UsingEOU 49
Summary 50
Micro projects 51
5. Logic Instructions 52
The logical operations 53
ANDA address and ANDB address 53
ORA address and ORB address 54
EORA address and EORB address 55
COMA, COMB address and COM address 56
Adding logic to the BASIC assembler 57
Bit manipulation 58
The shift instructions 61
The logical shift instructions, LSL and USR 62
The ROtate instructions, ROR and ROL 64
Adding shifts to the BASIC assembler 65
Labels and Data- RMS, FCB and FDB 66
Summary 69
Micro projects 70
6. Arithmetic Instructions 71
Assembly language arithmetic 71
Negative binary numbers-two's complement 72
The ADD and SUB instructions-the D register 74
Arithmetic with simple binary numbers 75
Arithmetic withtwo's complement numbers- the NEG instruction 76
The CLR, INC and DEC instructions 78
Adding arithmetic to the BASIC assembler 79
Extended precision arithmetic 80
Multiplication-thearithmetic shiftsand MUL 83
Binary coded decimal- the DAA instruction 86
vi
Adding shifts, DAA and SEX to the BASIC assembler 88
Summary 88
Micro projects 89
7. Branch Instructions 91
Unconditional branches and relative addressing 92
Relative addressing and the BASIC assembler 95
Conditional branches- the Condition Code register 98
Setting the condition codes directly-ANDCC and ORCC 101
The simple conditional branches 102
The signed conditional branches 105
The unsigned conditional branches 106
Addirlg conditional branches to the BASIC assembler 108
Testing without changing-CMP, TST and BIT 109
BSR and LBSR 112
Thinking BASIC- IF, conditional loops and FOR loops 113
Summary 115
Micro projects 116
vii
Program counter relative 157
Indirection 158
Summary of indexed addressing modes 1 61
Machine code details of indexed addressing 1 62
Direct addressing and the DP register 163
Adding the addressing registers to the BASIC assembler 164
A general multiple-precision arithmetic subroutine 167
Using Dragon sound 168
Summary 175
Micro projects 176
Index 230
viii
Chapter One
Why Assembler?
The only way to get the maximum power from any computer is to program
it in assembler. This is the only reason for using assembler as opposed to
friendlier computer languages such as BASIC. Even powerful, up-to-date
microcomputers such as the Dragon don't really run languages such as
BASIC fast enough for anything other than small programs and
applications where the user is prepared to wait. Until microcomputers
become much faster there will always be the need to take advantage of the
improved efficiency offered by assembler.
BASIC is easy
The transition from a high level language to assembler is bound to come
as something of a shock. For a start, a high level language lets the
programmer takes a good deal for granted and is therefore very much
more compact than assembler. One of the first things you now have to
realise is that one line of BASIC is often equivalent to several lines of
assembler. There is no denying that assembler is more difficult to learn and
use than BASIC. If this were not the case, then all personal computers
1
Language of the Dragon
would come equipped with assembler instead of the standard BASIC. The
fact that assembler IS more difficult should not put you off the task of
learning it even if you are a relative newcomer to computing. BUT, if you
don't already know BASIC then do not attempt to learn assembler until
you do - assembler isn't a good first language! For the rest of.this book it
will be assumed that you can write BASIC programs on the Dragon. If you
have this knowledge of programming, then learning assembler is well
within your reach. To make full use of assembler it is an advantage to
know something of binary numbers and one or two other topics but it is
better to leave these until they become necessary.
Which assembler?
2
Chapter I Why Assembler
Life is just a little more complicated than the last section would suggest.
A microprocessor doesn't work in terms of assembly language as written
by programmers but in 'machine code'. There is a lot of confusion about
the relationship between machine code and assembler that is worth
clearing up at this earty stage.
3
Language of the Dragon
The fact that a computer needs all of its instructions in the form of
numbers is something that we can do nothing about. However, there is
nothing stopping us from writing our programs in terms of easy to
remember 'command names' and then translating them into the numeric
codes used by the computer. For example, the 6809 machine code
instruction that plays the same role as GOTO in BASIC (i.e. it transfers
control from one position in a program to another) is 14 but it is much
easier to read and write the three letter command name JMP, which is
short for JuMP. Such easy to remember command names are usually
called 'mnemonics' because they help you to remember the commands.
(Mnemonic derives from the Greek word "mnemon", meaning "mindful".)
To this end long names are avoided in preference for three-, or at most
four-letter abbreviations. The collection of mnemonic commands is called
the machine's 'assembly language' and the act of converting it to the
numeric codes is called 'assembling the program'.
You should now be able to see that there is such a close connection
between machine code and assembly language that there is a tendency to
treat them as the same thing. But there are important distinctions:
An Assembler
4
Chapter 1 Why Assembler
You can see that an important component of this production cycle is the
conversion of assembly language to machine code. For a small program
this can be achieved by the programmer looking up the numeric
equivalents of each instruction in an appropriate table - such as the one
given in Appendix I. This method of conversion is known as 'hand
assembly' and if you are only going to write the occasional small assembly
language program it is good enough. However it soon becomes tedious if
you are writing any number of assembly language programs and error
prone if the program is at all long.
This sounds like a good idea but where do you get an assembler from?
There are a number of standard assemblers on the market and there is no
doubt that if you are going to use assembly language often then it is worth
investing in one of them. However, so that you can try out the ideas
explained in this book without having to resort to tiresome hand assembly
or an expensive assembler a simple assembler will be given using nothing
but BASIC. Writing an assembler in BASIC may sound like a difficult
program but, as you will see as things progress, it is fairly straightforward.
To make it even easier to understand, rather than quoting a listing of the
complete assembler, it will be built up chapter by chapter. In each case
only the commands and facilities discussed in the chapter will be added
and so, you should not only be able to understand the assembly language
of the Dragon, you should also be able to build up a picture of how an
assembler works. If you are not interested in how an assembler works,
then you can skip the explanations and just use the program (a complete
listing of which is given in Appendix II.) However, there is nothing like
understanding the principles behind software for demonstrating how
simple it really is.
5
Language of the Dragon
6
Chapter Two
You probably already know that the best way to think of a computer's
memory is as a l_arge collection of boxes or pigeon holes each capable of
storing a single number. These boxes or 'memory locations' are used by
the CPU to store information. Obviously to be of any use it is important
that each 'box' in the memory has a unique name so that the CPU can
refer to the box that it wants to store something in or retrieve something
from. This name is usually referred to as an 'address' and, as computers
work only with numbers, it makes good sense to restrict ourselves to
numeric addresses. Thus, each memory location has associated with it a
7
Language of the Dragon
number, its address, and a number stored within it, its data. The Dragon's
RAM occupies addresses from O to 32767 and each memory location can
store a number in the range O to 255. The reason for the limits being 32767
and 255 are connected with the way that a computer actually stores
numbers in binary and this will be discussed a little later in this chapter.
The storage of data implies that some kind of memory is in use and so it
is with the CPU. Within the CPU are a small number of very special
memory locations called 'registers'. To be absolutely clear, registers have
nothing to do with the computer's main memory and addressing methods.
They are more like internal 'notepads' that the CPU uses to hold data
while it is working with it. As there are only a small number of registers
inside the CPU it is usual to give each one a name rather than a numerical
address. There are nine registers inside the 6809 microprocessor that
makes up the Dragon's CPU. Rather than examining them all in one go, it
is less confusing to introduce them as the need arises. Perhaps the two
most useful registers are the A and 8 accumulators. The reason why they
are called accumulators is a little difficult to explain at this stage but,
roughly speaking, an accumulator is a register where data cannot only be
stored but can also be changed (i.e. the result is 'accumulated'). The ways
8
Chapter 2 Registers and Operations
address data
109
108
107
1 06
1 05
1 04 u
1 03
1 02
101
100
memory
in which data can be changed are fairly limited and it is this limitation that
generally makes assembly language programming more difficult than say
BASIC.
The 6809's A and B registers are just like ordinary memory locations in
that they can each hold a single number in the range O to 255. This means
that the contents of a single memory location can be transferred to either
the A or the B register. The 6809 carries out the instructions LOA, short
for LoaD the A register, and LOB, which is short for LoaD the B register,
for just this purpose. So, when the 6809 comes to obeying the numeric
code in a machine code program that is associated with LOA, it loads the
A register, but from where? Obviously an instruction to load a register
from memory must include information about which memory location is to
be used. The complete form of the LOA is in fact LDA 'address' where
'address' is a number that is used as the address of the memory location
whose contents are transferred (or loaded) into the A register. So, for
example, LOA 421 would read the contents of memory location 421 and
store them in the A register. It is important to notice that following the
transfer the contents of memory location 421 is unaltered. Indeed the only
thing that has changed is that the A register now has the SAME contents
as location 42 1 .
10
Chapter 2 Registers and Operations
value in it and, when that happens, the value that rt formerly contained is
lost forever - in other words storing a new value in memory {or a register
for that matter) overwrites the old value. Moreover, retrieving (i.e. reading)
the contents of a memory location (or again a register) doesn't alter its
contents in any way - its contents are simply copied.
A short program
Now that we have four assembly language instructions LOA, LOB, STA
and STB we can write a very simple program -
LDA 100
LDB200
STA200
STB 100
This program first loads the A register from memory location 100 and the B
register from memory location 200 and then stores A in 200 and B in 1 00 so
effectively swapping the contents of the two memory locations. Notice
that even for this very simple operation of swapping the contents of two
memory locations the data still had to be brought inside the CPU before
anything could be done to it! This is such a simple program that hand
assembling it is not too much trouble and is also quite instructive. The
code that corresponds to LDA is 146, for LDB it is 214, for STA it is 147
and for STB it is 215. (If you have tried to use the table in Appendix I to
look up the codes for LOA etc you will have noticed that the values it
contains are all in hexadecimal. Don't let this worry you now. By the end
of the next chapter you will be confident about using hex. You may also
have been puzzled by the fact that there is more than one choice of code
for each mnemonic. Again don't worry about this for the moment it will
be fully explained in the next chapter!) So in machine code the program is
146100
214 200
147 200
2 1 5 1 00
and perhaps now you can see why programmers prefer to use assembly
language mnemonics instead of machine code!
11
Language of the Drsgon
address data
59
58
57 100
56 21 5
55 200
54 147
53 200
52 21 4
51 100
50 146
12
Chapter 2 Registers and Operations
The list of eight numbers given above is indeed a machine code program
that the 6809 inside the Dragon will obey to swap the contents of memory
locations 100 and 200. The next question that has be be asked is how does
the 6809 ever get to 'see' the list of numbers that constitutes the program
that we want it to obey? At the moment the list exists only on paper and
the 6809 has no access to itl Obviously the program must be stored in
memory as this is the only place that the CPU can obtain any sort of
information from.
The fact that machine code program is stored in memory should not
come as, any great surprise after all where else is a BASIC program
stored? However, there are some important differences between the way a
BASIC program and a machine code program are stored in memory. ln
particular the lines of a BASIC program are 'marked' by line numbers so
that at any given moment the computer is obeying a particular line number
but the commands of a machine code program are only 'marked' by the
address of the memory location that they are stored in. Notice that a single
instruction can occupy more than one memory location and so correspond
to more than one address. For example the LOA 1 00 instruction takes two
memory locations and is stored in 50 and 51 . In obeying the program the
6809 would first carry out the instruction stored starting at 50 (i.e. the LOA
100) it would then move on to carry out the instruction starting at 52 and
so on until the program was finished. (Notice that in this simple example
the problem of stopping the computer at the end of the program has been
totally ignored!)
You should be able to see that the address that an instruction is stored
at can function in exactly the same way that line numbers do in BASIC.
That is the 6809 can keep track of where it is in a program simply by
remembering the address of the instruction that it is carrying out. Also, like
a BASIC program, a machine code program is obeyed in order of
increasing address, unless it is made to do otherwise by the machine code
equivalent of a GOTO, a GOSUB or a RETURN. As you might guess, the
address of the instruction that is being carried out is kept inside the CPU in
yet another register - the PC or Program Counter - bringing the total
number of registers that we know about to three. To make the 6809 obey
the swap program the PC register would first be loaded with 50 (how, will
be explained later) then the instruction starting at address 50 would be
carried out and the PC register adjusted to point to the next instruction
and so on until the program was complete.
13
Language of the Dragon
The only thing that you have to be careful of is that the area of memory
that is used to store the program isn't being used for something else. For
example, it wouldn't be a good idea to store the swap program starting at
memory location 100 (because this is one of the memory locations that is
swapped and so we have to assume it contains data.) You should now be
able to see that the Dragon's memory stores only numbers but these
numbers can serve two different functions. They can be data that a
program operates on or they can be instructions within machine code
programs. Sometimes the CPU takes data from memory and sometimes it
takes its next instruction.
Summary
So far the only machine code instructions that have been explained are
LOA, LOB, STA and STB. However, a lot of new ideas have been
introduced in this chapter, so it is worth gathering them together and
attempting to summarise the main ideas:
5) The address of the instruction being carried out is stored inside the
CPU in the PC or Program Counter register. Instructions are normally
carried out in order of increasing address.
6) The 6809 has two registers used to manipulate data, the A and B
registers.
14
Chapter 2 Registers and Operations
Each line starts with an optional space then there are a number of
letters forming the mnemonic then at least one space followed by
digits forming the address.
The program that follows will assemble the swap program given earlier if
you type it in line by line. After the last line of the program type END and
then the BASIC assembler will produce a listing of the machine code
identical to that produced by hand assembly.
1 REM BASICASSEMBLERV2.1
10 DATA LDA,146,LDB,214,STA,147,STB,215,=,999
500GOSUB1 000
510 GOSUB2000
520 GOSUB3000
530 GOSUB4000
540 GOSUB 5000
550 GO SUB 6000
560 1 = 1 + 1
570 I F I> TTHEN STOP
580G00520
1000DIMA$(50)
1010 1 = 0
1 020 P = 50
15
Language of the Dragon
1030 RETURN
2000 INPUT L$
2010 IFL$ = "END"THEN T = I:I = 1 :RETURN
2020 1 = 1 + 1
2030 A$ill = L$
2040 GOT02000
3000J = 1
3010 1F MID${A$11l,J, 1 1 = " "THENJ =J + 1 :GOTO3010
3020 M$ = MID${A$11),J, 1 I
3030 J = J + 1
3040 IF MID${A$11l,J, 1 1< > " " THEN
M$ = M$ + MID${A${I),J,1 I:J =J + 1 :GOTO 3040
3050J = J + 1
3060RETURN
4000 RESTORE
4010 READC$,C
4020 IFC$ = "ZZZ"THEN ER = 1 :GOTO 9000
4030 IFC$= M$THEN RETURN
4040 GOTO401 0
5000 A = VAL{MID${A${I1,JII
5010 RETURN
After you have typed the BASIC assembler in it is important that you
save it on tape because in subsequent chapters it will be improved on and
added to. The program is written using BASIC subroutines for each job
that the assembler must carry out. This makes later modification a matter
of altering subroutines. A brief description of the program follows-
16
Chapter 2 Registers and Operations
1000 Initialisation
If you can't follow the workings of the BASIC assembler so far then
don't worry: just type it in and see that it really does change the assembly
language in the program swap to machine code.
17
Language of the Dragon
Reserving some memory is easy with the Dragon. The command CLEAR
s,h will reserve s memory locations for string storage and move the top of
memory down so that memory location h is the highest that will be used
by BASIC. In other words CLEAR s,h will reserve memory from address
h + 1 up to 32767. Once some memory is available, tranferring machine
code to it is easy using the BASIC command POKE a,d which will store
the number 'd' in the memory location whose address is 'a'. Adding these
ideas to the BASIC assembler gives -
5 CLEAR 1000,28671
1 020 P = 28672
18
Chapter 2 Registers and Operations
With these changes, the BASIC assembler now leaves the machine
codes stored in the reserved memory when it finishes. If you want to
check that this is true then you could use the BASIC command PRINT
PEEK(a) to examine the contents of each memory location.
All that is left now is to discover a way of actually running the machine
code stored in the reserved memory. Once again Dragon BASIC makes
this particularly easy for us in that if provides the EXEC 'address' command
which will start the 6809 obeying a machine code program whose first
instruction is stored at 'address'. So, to start the swap program running,
all you would have to type is EXEC 28672. However, DON'T try this for the
swap program because apart from it not doing anything useful (or visible)
it doesn't contain any way to stop itself or to return control to BASIC!
19
Language of the Dragon
Micro projects
1 ) Using the information given in this chapter, hand assemble the two line
addition program in the last section. Show the address that each item of
machine code is stored in given that the program is to start at address
28672.
2) If memory location 200 contains 56 and memory location 201
contains 4 before the program is run what do they contain after it is run
and what does the A register contain?
20
Chapter Three
Addressing
There are two parts to any assembly language instruction the operation
to be carried out and the address of the memory location that it is to be
carried out on. The subject of how assembly language instructions can
address memory is very important and in this chapter some of the simpler
but more useful methods are described. As addressing is about the use of
numbers and how they are stored inside the computer, it is difficult to
avoid the subject of binary and hexadecimal numbers. Both of these topics
are treated in this chapter, although only in as much as they are useful to
the assembly language programmer.
21
Language of the Dragon
Direct Addressing
If you go back and look at the few examples given in the previous
chapter you will indeed find that they fit into the format of
operation I address
but what you may not have noticed is that all of the addresses were
smaller than 255. This allowed the address to be stored in a single memory
location following the machine code for the instruction. For example, LOA
255 can be assembled to 146,255 and each number can be stored in a
single memory location but what about LDA 256? Remember, a single
memory location can only hold numbers in the range O to 255. The answer
is of course to use more than one memory location to store the address
but this takes us to a second method of addressing memory called
'extended addressing'. In short, direct addressing can be used to specify
an address in an instruction only if the address is in the range O to 255.
Obviously, this is very restrictive and, as you might imagine, direct
addressing is not often used. (In fact there is rather more to direct
addressing than it is worth going into at this stage and, at a more
advanced level, it does have some advantages over extended addressing.)
However before we can move on to using extended addressing it is worth
looking at some details of how numbers are actually stored in memory.
So far all that has been said about the nature of a single memory
location is that it can store a number in the range O to 255. In fact, a
memory location doesn't store a decimal number at all. Instead, it stores a
pattern of eight zeros and ones, in other words eight 'bits'. A group of ·
22
Chapter 3 Addressing
eight bits forms a single unit, referred to as a 'byte'. What this pattern of
eight bits represents is not something that is uniquely defined. For
example, you might use each bit to represent the state, open or closed, of
eight doors in a house. One of the differences between BASIC and
assembly language is the BASIC has numbers and characters to work with
but in assembler the only raw material is the bit pattern. It is important to
realise that, even though the eight bits that are stored in a memory
location are normally interpreted as a number, this is just one
interpretation. However, this conventional interpretation is so important it
is worth going over the details of standard 'binary numbers'. Later on it
will be necessary to change the way that the pattern of bits is interpreted
to include negative numbers.
For most people, the decimal system is the best known way of
representing numbers. Using the digits O to 9 it is easy to count up to nine
objects. The answer to how to count beyond 9 is so familiar to all of us
that it hardly seems a problem. The decimal system uses a second digit to
record the number of groups of ten that have been counted, a third digit
for the number of hundreds and so on. This is called a 'place value' system
since each place represents a multiple of the 'base' value. In other words,
the number 245 is to be understood to mean two lots of 100, four lots of 10
and five lots of 1 . The binary system is also a place value system that
works in exactly the same way as the decimal system - except that only
the figures 0 and 1 are available for counting. This restriction gives rise to a
place value system that counts in lots of 1 's,2's,4's,8's and so on. So the
binary number 1 0 1 is to be read from left to right as one lot of 4, no lots of
2 and one lot of 1 , giving the number that we call five in decimal. As
another example, consider the binary number 1010110. This can be written
as:
Notice that the place value increases by a factor of 2 for each place to the
left and the decimal equivalent is just the sum of the place values wherever
a 1 occurs.
It is not too important that you know how to convert binary to decimal
and vice versa but it is important that you are not worried by binary
23
Language of the Dragon
numbers and are prepared to look up the extra details that you need to
know. Now the reason why a memory location can hold numbers in the
range 0 to 255 should be clear. The smallest number that can be
represented by eight bits is 00000000 or 0 and the largest is 1 11 11 11 1
which, if you convert it to decimal, gives 255.
As you can see, the place value increases very rapidly and this means that
hex numbers use fewer digits than decimal for the same number.
You don't have to worry about converting hex numbers to decimal and
vice versa because the Dragon can do it for you. To convert from decimal
to hex use the HEX$ function - e.g. PRINT HEX$(41743) - and to convert a
hex number to decimal simply precede it by &H - e.g. PRINT &HA30F. In
fact the Dragon can do a little better than just converting hex numbers to
decimal because you can use a hex number anywhere that you can use an
ordinary number.
24
Chapter 3 Addressing
hex bin
0 0000
1 0001
2 0010
3 001 1
4 0100
5 0101
6 01 1 0
7 01 1 1
8 1000
9 1001
A 1010
B 1 01 1
C 1 1 00
D 1 1 01
E 1110
F 1111
T o convert from hex t o binary all you have t o d o i s take each hex digit in
turn and write down its four bit binary equivalent from the table, For
example the binary equivalent of F3A2 is -
F 3 A 2
1111 0011 1 01 0 0010
To convert from binary to hex all you have to do is form the bits into
groups of four starting from the right then look up each group in the above
table. For example, to convert the number 1 01 1 01 1 1 0 to hex -
0001 1 01 1 0 I 1110
1 6 D
Perhaps the best reason for using hex numbers is the simple observation
that a two figure hex number corresponds to eight bits and so can be
stored in a single memory location. In other words a single memory
25
Language of the Dragon
location can store a hex number in the range 00 to FF. In the same way a
four figure hex number can be stored in exactly two memory locations and
so on. It is this correspondence between the number of figures in a hex
number and the number of memory locations it takes to store it, coupled
with the natural way hex and binary work together, that makes hex
numbers so useful in assembly language programming, From now on,
unless there is a good reason otherwise, all of the numbers used in this
book will be hex numbers. Although the Dragon uses &H in front of a
number to indicate that it is in hex it is almost universal in assembly
language to use $ in front of a hex number and this will be used in the rest
of this book. So 10 is ten but $10 is 16!
Extended addressing
After a long digression into binary and hex numbers it is time to return
to 6809 addressing modes. Direct addressing uses a single memory
location to store the· address of the memory location to be used in the
operation. Extended addressing takes two memory locations to store the
address. This corresponds to an address in the range O to 65535 which is
as much memory as the 6809 can handle. Thus using extended addressing
you can select ANY memory location within the Dragon and there is no
need to extend the number of memory locations used to store an address
to three or more.
LDA$3F
isa direct address because it is less than $FF but
LDA$3F2C
needs two memory locations for the address and so it is extended.
What is more interesting is that the machine code for the two instructions
is different. The code for LOA with direct addressing is $96 and its code
using extended addressing is $B6. (Notice the use of hex numbers to
represent the machine codes.) Notice that this means that it is no longer
possible to convert assembly language mnemonics to machine code simply
by looking them up in a table. Now we have to take into account the
addressing mode used as well as the mnemonic. If you look at the row
26
Chapter 3 Addressing
containing the mnemonic LDA in the table of Appendix I, you will see that
there is a range of machine codes, each one corresponding to LDA used
with a different addressing mode. You should be able to find the two
values quoted above in the columns headed 'direct' and 'extended'. From
now on, the BASIC assembler is going to have to examine both the
mnemonic and the addressing mode before it can determine the machine
code for a given instruction. So
LDA $3F2C
hand assembles to
B6 3F 2C
A practical program
Now that we can address all of the 6809's memory it is possible to write
a program that will add the contents of any two memory locations
together. In other words, the program will be the assembly language
equivalent of the one line BASIC program -
10 A � B + C
First, i t i s important t o notice that, unlike the BASIC program, all that the
assembly language program can do is to add two numbers in the range 0
to $FF. For the sake of simplicity let's use memory' location $7FFF to store
the result and $7FFD and $7FFE to store the two numbers to be added
together (see fig 3.1). ($7FFF is 32767 which is the highest Dragon address
occupied by RAM used for storing programs. l The program has to perform
the assembly language equivalent of:
As already explained at the end of Chapter Two you cannot implement this
idea as it stands in assembly language. The reason for this is that the only
add instructions that the 6809 has add the contents of a memory location
27
Language of the Dragon
<
Result --+ $7FFF
$7FFE
Two numbers
to be 1---------1
added
$7FFD
28
Chapter 3 Addressing
to the A or B registers, where they also leave the result. So the program
has to written
LDA$7FFD
ADDA$7FFE
STA$7FFF
RTS
You should recognise this as being essentially the same as the addition
program given at the end of Chapter Two but now using extended
addressing. The instruction RTS has been added to the end of the
program so that when it is finished the program returns to BASIC rather
than running on out of control. The details of RTS will be discussed later
but, for now, all that you have to know is that assembly language program
that you intend to run should always end with RTS.
Once again it is worth hand assembling the program to see what the
BASIC assembler has to do. The only real difference is that now, when
looking up the mnemonic codes in Appendix I, you have to take into
account the addressing mode used. In this case the extended mode is used
throughout, apart from RTS for which there is only one choice of machine
code anyway! If the program is loaded into memory starting at $7000
(which is the same as 28672 used in Chapter Two) then the finished
machine code program is -
7000 B67FFD
7003 BB7FFE
7006 B77FFF
700939
Notice that the listing is given totally in hex but the usual $ sign
signifying a hex number has been left out to make the listing more
readable. Also notice how much neater the listing is for being in hex: there
are always four figures to the address in the first column, every pair of hex
figures is stored in its own memory location, with each pair stored
consecutively. Thus 86 is stored in memory location 7000, 7F at 7001, FD
at 7002 and so on to 39 stored at 7009. The time has now come to modify
the BASIC assembler so that it can handle different addressing modes and
at last run our first assembly language program
29
Language of the Dragon
DATA mnemonic,code1,code2,code3,code4,code5
Where codel through code5 are the machine codes for the five addressing
modes 1 to 5. The names of these modes are -
1 Immediate
2 Direct
3 Indexed
4 Extended
5 Inherent
The only problem is that any given mnemonic may not use all five
addressing modes. To record the fact that any addressing mode is illegal
with the mnemonic in question a code of -1, which normally cannot occur
is used. Once the format of the DATA statements has been fixed the rest
of the assembler follows. -
5 CLEAR 1000,&$6FFF
10 DATA LDA,&H86,&H96,&HA6,&'-IB6,-1
11 DATA LDB,&HC6,&HD6,&HE6,&HF6,-1
12 DATA STA,-1,&H97,&HA7,&HB7,-1
13 DATA STB,-1,&HD7,&HE7,&HF7,·1
14 DATA ADDA,&H8B,&H9B,&HAB,&HBB,·1
15 DATA ADDB,&HCB,&HDB,&HEB,&HFB,·1
16 DATA RTS,·1,-1,-1,-1,&H39
99 DATA ZZZ,·1,-1,-1,-1,-1
30
Chapter 3 Addressing
2000 INPUT L$
201 0 IF L$ = "END" THEN T = 1:1 = 1 : RETURN
2020 1 = 1 + 1
2030 A$(1) = L$
2040 GOTO 2000
3000 J = 1
3010 IF MID$(A$111,J,1 I = " " THEN J = J + 1 :GOTO 301 0
3020 M$= MID$IA$11),J, 1 I
3030 J = J + 1
3040 IFJ< = LEN(A$IIIITHEN IFMID$IA$(11,J, 1 )< > " "THEN
M$= M$+ MID$(A$( 11,J,1 ):J =J + 1 :GOT03040
3050 J =J + 1
3060 RETURN
4000 RESTORE
"="
401 0 READ C$
401 5 FOR K = 1 TO 5: READ C(K): NEXT K
4020 IF C$ = THEN I = I + 1 :ER = 1 :GOTO 9000
4030 IF C$ = M$ THEN RETURN
4040 GOTO 401 0
31
Language of the Dragon
9010 RETURN
In going to this second version, the opportunity has been taken to change
all of the relevant constants to hex and to change the listing of the
program to hex. The main changes are in subroutines 40 0 0 , 50 0 0 and 6 0 0 0 .
Subroutine 40 0 0 now scans through the DATA statements t o find the
mnemonic stored in M$ but now, when it finds it, it returns the five
possible codes in the array C rather than a single code. Subroutine 50 0 0
now has not only t o work out the address following the mnemonic but has
to determine the type of the address and so select the correct code from
the array C. A new subroutine has been added (55 0 0 ) which called at the
start of subroutine 50 0 0 . Subroutine 550 0 takes the addressing information
and packs it character by character into the variable AF$ (AF standing for
Address Field). As this transfer is accomplished, a number of changes are
made. First, any blanks that have been included are removed and,
secondly, any $ signs are changed to &H so that the BASIC VAL function
can work the address out correctly. Subroutine 50 0 0 then sets the variable
TYPE to 2 if the address is less than 256 and to 4 if it is greater than 255. If
there is no address field i.e. if AF$ = '"' then the instruction must be like
RTS and then the appropriate type is 'inherent' or TYPE = 5 . Subroutine
6 0 0 0 is changed to PRINT and POKE a different number of items
depending on the addressing mode.
32
Chapter 3 Addressing
Notice that only DATA statements for the 6809 instructions that have
been described so far have been included in the program. In principle there
is no reason why the list of DATA statements shouldn't be extended to
include all of the instructions in the operation code table given in Appendix
I. However there are a great many instructions in the table and typing in all
the DATA statements in one go is no small task! If you don't feel like
tackling this particular project then the easier alternative is to add the
appropriate DATA statements as instructions are encountered in future
chapters. An advantage of this method is that the BASIC assembler grows
as your knowledge does!
Trying it out
After typing in the above version of the BASIC assembler the obvious
thing to so is to try to assemble and run the simple addition program. RUN
the assembler and type in
LDA$7FFD
ADDA$7FFE
STA$7FFF
RTS
END
You should see the same listing that you got from the earlier hand
assembly. After the assembler has finished the machine code is stored in
memory starting at $7000. Once again you can check that this is so by
PEEKing each of the memory locations i.e. PRINT HEX$(PEEK(&H7000))
etc. You can run the machine code by simply typing EXEC &H7000. If
everything goes according to plan (or rather program) you should see the
usual Dragon OK printed on the screen indicating that the machine code
program has returned control to BASIC. If anything else happens your
only hope of regaining control of the machine is to press the reset button.
If you are lucky your program will be intact, on the other hand it might not
be! It is worth learning very early on that assembly language is not as
friendly or as safe as BASIC. If you make a mistake in a machine code
program you won't get a error message, just a Dragon that behaves
oddly.
33
Language of the Dragon
If everything did work OK, and with such a short program there is no
reason why it shouldn't, then you should find the the content of memory
location $7 FFF is indeed the sum of the contents of $7FFD and $7 FFE. The
easiest way to check that this is true is -
PRINT PEEK(&H7 FFF),PEEK(&H7 FFDl,PEEKl&H7 FFE)
You can use POKE to change the contents of the two memory locations
$7 FFD and $7 FFE and then EXEC the machine code again just to make
sure that it all works.
Immediate addressing
So far, the only two addressing modes that we have looked at - direct
and extended - are hardly different enough to give the flav0ur of the
subject. After extended addressing, the most frequently used addressing
mode is probably 'immediate addressing' and so it is important to
introduce this mode as early as possible. Consider the problem of adding a
constant, for example, 3 to the contents of a memory location. So far, the
only way that this could be done would be by using the addition program
used as an example in this chapter. Immediate addressing is sometimes
called 'immediate data' because it allows the data to be stored in the
memory location following the machine code for the instruction. Notice
that in this case the number following the instruction code IS the data not
the address of the data. In assembly language, immediate addressing is
indicated by a # sign. For example,
LOA jl$3
loads the A register with 3 in contrast to
LOA $3
which loads the A register from memory location 3. The hand assembly of
LOA #3 is -
86 03
To change the BASIC assembler to handle immediate addressing is
easy. Simply add the following lines -
34
Chapter 3 Addressing
6060 TYPE = 0
6070 RETURN
Notice that immediate addressing doesn't make sense with all types of
instruction. For example, STA #3 is illegal because there would be no
point in storing the contents of the A register in the memory location
following the instruction code so what would the 3 mean? Immediate
addressing only makes sense when used with instructions that obtain data
from memory and not with those that store data in memory.
Sum mary
6) Hex numbers are more convenient then decimal numbers and are
almost always the standard way of writing addresses, data and
instruction codes in assembler.
35
Language of the Dragon
Micro Projects
36
Chapter Four
Imagine how limited BASIC would be if you didn't know about the GOTO
statement. Without GOTO, you could not code jumps or loops in your
program. This is such a fundamental part of programming in any language
that it is important that you become familiar with the assembly language
equivalent of GOTO. This also leads us on to consider what is really the
last new idea to be included in the BASIC assembler - labels. If you have
been disappointed by the example assembly language programs in the
earlier chapters because of how little they manage to do, then you will be a
little happier with the main example in this chapter, at least it displays
something on the screen!
The J M P instruction
As described in Chapter Two, the address of the memory location that an
instruction is stored in is in some ways like the line number of a BASIC
command. In particular the assembly language instruction -
JMP address
will cause the next instruction to to be the one starting at 'address'. There
are three addressing modes that can be used with the JMP instruction,
direct, extended and indexed, the last of which is yet to be described. So
JMP $4323 is a valid JMP instruction which causes the instruction at $4323
to be carried out next. If there isn't an instruction stored at this address
then things will go very wrong. Once again, unlike BASIC, machine code
won't give you a friendly error message to tell you that there is no such line
number, rather address, because of course the address referred to in a
JMP instruction always exists! What happens if you JMP to a memory
37
Language of the Dragon
location that doesn't contain machine code is that the 6809 will obey
whatever collection of numbers the memory does contain as machine code
and so the result is entirely unpredictable behaviour. For this reason you
have to be very careful that JMP instructions do go to the correct location.
The JMP instruction look simple enough to use for any one familiar with
the GOTO instruction. However there is fundamental problem that both
GOTO and JMP share. lf you are in the middle of writing a BASIC
program and you know that you want to GOTO a line further on in the
program then how do you know its line number? The trouble is that you
only know the line numbers of commands that you have already written.
This is known as the 'forward jump' problem (see fig 4.1 ). The usual
solution in BASIC is to either guess the line number and then correct the
GOTO statement when the program is finished or just leave it undefined
and go back and fill in the missing line number later. In assembly
languagge the problem is agravated because while you are writing the
program using mnemonics you don't know the address that any given
instruction will be stored at, this is something that is only discovered when
you assemble (by whatever method) the program. This makes 'backward'
jumps difficult to handle, let alone forward jumps! For example, suppose
that you are writing a program that will load the A register from a number
of memory locations in turn and store its contents in a single location (why
you might want to do this will become clear after the sound producing
examples in Chapter Nine.) The program that you would write might look
something like -
LDA$7F00
STA $FF20
LDA$7F01
STA$FF20
JMP??/1
Where the four question marks indicate that the address for the JMP is
unknown. To make the program into a loop the JMP should transfer
control back to the first instruction of the program. The address of the first
instruction obviously depends on where the program is loaded into
memory. If the program is loaded, as in all the previous examples, starting
at $7000 then obviously the correct address for the JMP instruction is JMP
$7000. However, suppose you wanted to JMP to the third instruction in
38
Chapter 4 Jumps, Loops and Labels
program to
be written
39
Language of the Dragon
the program, i.e. LOA $7F01 , how would you know its address? The
answer is that you would have to assemble the program! This doesn't
sound too difficult until you realise that if you make any changes to the
program that inserts or deletes instructions then the chances are that the
address of the instruction that you are JMPing to will change and, to make
the program continue working, you have to change the JMP addresses. If
you think about the difficulties of actually using an instruction that jumps
to a particular address then you will soon see the need for adding address
labels to the BASIC assembler.
Address labels
then the meaning of the program would have been clear. The final JMP
instruction is obviously intended to transfer control to the instruction
'labelled' START so forming a loop. When the program is assembled
START as used in JMP START has to be changed to an address. To be
more precise it has to be changed to the address of the instruction that it
labels. START is an example of an 'address label' (or just 'label') There are
just enough similarities between a BASIC variable and a label to be
confusing. A BASIC variable has a value associated with it and so does a
label (i.e. the address of the instruction that it labels) but a label is used
only in the translation of assembly language to machine code whereas a
BASIC variable exists while a program is running. It is better to think of a
label as more like a mnemonic code that stands for an address rather than
as one which stands for machine code.
There are two ways that a label can appear within a program:
40
Chapter 4 Jumps, Loops andlabels
Adding a label facility to the BASIC assembler is very easy. First, a new
pair of arrays needs to be defined, T$ to hold the labels and T to hold their
corresponding address values. When a label is defined, T$ is searched and
as long as the label isn't already in T$ (in which case an error is reported) it
is added to the list and its addre�s is stored in T. The only problem is, how
do we tell the difference between a label and an ordinary mnemonic code?
Some assemblers demand that a label should always start at the beginning
(i.e. without any blanks before it) and a mnemonic should always have at
least one blank before it. Following the convention of DASM, the
assembler from Compusense, labels will be distinguished by starting with
"@". So legal labels take the form:
@START
@LOOP
etc.
41
Language of the Dragon
1 400 RETURN
3500 S$ = M$
3510 GOSUB 7000
3520 IF F> 0 THEN ERR = 0:GOTO 9000
3530 LC = LC+ 1
3540 T$ILC) = M$
3550 TILCI = P
3560 GOTO 3010
7000 K = 1
7010 IF K> LC THEN F = 0:RETURN
7020 I F T$IKl = S$ THEN F = K:RETURN
7030 K = K+ 1
7040 GOTO 701 0
Apart from the updates to the existing subroutines, this version includes
two new modules. Lines 3500 to 3560 check for the existence of the label
in the array T$ and, if it isn't there, it adds it along with the current address
in T. Subroutine 7000 searches for the string S$ in the array T$. On, return
42
Chapter 4 Jumps, Loops and labels
the variable F is 0 if the string wasn't found and equal to its position in the
array if it is. Lines 5550 to 5600 detect a label in the address field, use
subroutine 7000 to find it in the array T$ and then substitute the address
stored in T. Also notice that the DATA statement for the JMP instruction
has been included.
@START LDA$7FF0
STA$FF20
LDA$7FF1
STA$FF20
JMP @START
The ability to handle labels can be seen in the way that the last line is
assembled to -
7E 700C
Now that labels can be used, the JMP instruction is easy to use. All you
have to do is label any instruction in the program that you want to JMP to
and, as long as you don't define the same label twice, you can JMP to it as
often as you like. However, this simple picture is still spoiled by the
problem of forward jumps.
The BASIC assembler V4. 1 will handle labels but only if they are defined
before they are first used in an address field. For example, if you try to
assemble -
LDA$7FF0
JMP @SKIP
STA$FF20
@SKIP LDA$7FF1
END
43
Language of the Dragon
you will get an error message because when the assembler reaches the
JMP @SKIP instruction the label @SKIP is not yet defined - it is further
down the program. This restriction on the use of labels is so serious that, if
allowed to persist, it would make assembly language programming very
difficult. Fortunately the solution is quite simple. To make sure that any
label that might be used in a program is defined, all that the assembler has
to do is read through the program, picking up all the label definitions
before it attempts to produce a final machine code assembly. In other
words, the assembly should make two passes though the assembly
language program. The first pass just serves to record the label definitions
and the second pass uses these definitions to produce a correctly
assembled program. Notice that the first pass that the assembler makes
through the program has to assemble the program the best it can so that
the instructions take up the correct amount of memory and the labels are
defined at their correct addresses. This implies that the easiest way to
change the V4.1 assembler into a two-pass assembler is just to make it
automatically run twice over any assembly language program, the first
time ignoring any errors that are generated because labels are undefined
and the second time using the definitions collected in the first pass.
initialise l
FOR PASS - 1T02
initialise 2
assemble
NEXT PASS
and be careful about where things are initialised. For example, there would
be no point in doing the first pass if the array T$ used to hold the labels
was cleared between passes! The only other changes to the assembler
involve the use of the variable PASS to decide when an error should be
reported. If an undefined label is encountered then this is now only an
44
Chapter 4 Jvmps, Loops and labels
error if the assembler is on pass 2. Also, as all the labels should have been
defined after pass 1 , discovering that a label is already in T$ isn't an error
in pass 2. Make the following modifications to the BASIC assembler:
5 1 5 FOR PASS = 1 TO 2
5 1 8 I= 1 : P = &H7000
If you run the new version of the assembler on any of the previous
examples you will find that you now get a listing of the machine code
twice - once on each pass through the program. Although the second one
is the only one that has any chance of being correct, the first listing does
provide some information about the way that the assembler is working and
so it will be left as a feature for the time being, until a better version of
subroutine 6000 is written later on.
When an undefined label ls encountered on the first pass the value zero
is used as its temporary address so · that the rest of the program can be
assembled. However, the current way that the assembler selects direct or
extended addressing causes something of a problem. For example, if you
try-
JMP @SKIP
LOA lf0
@SKIPLDA jt1
(a correct program that doesn't do anything useful!) you will find that on
the first pass the JMP @SKIP is assembled as a direct address because
@SKIP has the temporary address of 0 but on the second pass JMP
45
Language of the Dragon
LDA $30
Now the BASIC assembler will handle forward and backward JMPs by
making two passes through the program correctly. To check this, try
assembling any of the previous examples. Make sure that the address
following a JMP ins..truction really is the address of the first memory
location in which the correct instruction is stored.
46
Chapter 4 Jumps, Loopsand LBbels
Now that the assembly language equivalent of the BASIC GOTO has
been introduced, it is only a small step to the assembly language
equivalents of the BASIC GOSUB and R ETURN. The JSR address (Jump
to SubRoutine) will transfer control to the instruction stored at 'address'
but like the BASIC GOSUB it causes the 6809 to store the address of the
instruction following it. This stored address is used by the instruction RTS
(ReTurn from Subroutine) to transfer control back after the JSR. Thus the
JSR and RTS pair exactly mimic the behaviour of the BASIC GOSUB and
RETURN instructions and so allow us to write and use assembly language
subroutines.
The JSR instruction can be used with the same three addressing modes
as the JMP instruction - direct, extended and indexed. The fact that the
RTS instruction is a little odd when it comes to addressing modes has
already been mentioned. The RTS instruction does use an address, but the
address is supplied by the 6809. In other words, when you use the RTS
instruction, you do not have to explictly give the return address and in this
sense the address is 'inherent' in the instruction. There are other
instructions like RTS that sometimes do not need a programmer-supplied
address and this gives us a fourth addressing mode to add to direct,
extended and immediate: 'inherent addressing'. (Corresponding to
TYPE = 5 in the BASIC assembler.I
Before going on, enter the DATA statement for the JSR instruction in
the BASIC assembler IRTS is already present) :
1 8 DATA - 1,&H9D,&HAD,&HBD,-1
Since the JSR instruction uses the same addressing modes as the JMP
instruction it make sense to allow labels to be used in the same way.
However, the JSR instruction is often used to gain access to machine
code subroutines already present in the BASIC ROM and this makes the
use of labels a little more complicated. For example, there is a machine
code subroutine that will print a character on the Dragon's text screen that
starts at $800C. The character to be printed is stored as its ASCII code in
47
Language of the Dragon
The first instruction loads the A register with $41 which is the ASCII code
for the letter A. The second instruction calls the subroutine at $800C which
prints the A on the screen and then returns control to the JMP instruction
which repeats the program forever - or until you press the reset button. If
you enter this program using the BASIC assembler you can run it using the
usual EXEC &H7000. After the screen has filled with As you may find it
difficult to see the As being printed - this is your first taste of how much
faster assembly language is than BASIC!
48
Chapter 4 Jumps, Loops and Labels
Using EQU
Now that the BASIC assembler can define labels using the EOU pseudo
op, the previous 'print A on the screen' program can be written as-
@PRINT EOU $800C
@LOOP LDA jl$41
JSR @PRINT
JMP@LOOP
END
Once again you should be able to enter the program to the BASIC
assembler and then run it using EXEC &H7000 with the same result as
before.
49
Language of the Dragon
The interesting thing about EQU is that, once you have introduced it,
there are all sorts of other ways that you can use labels. For example, the
second instruction in the program loads the A register with the ASCII code
for the letter 'A' but this is not something that is very clear just by reading
the program. If however the program is written as -
then the use of a label as part of the immediate address field of the LDA
instruction once again makes the program slightly more readable. What
might surprise you is that this program can be assembled by the current
version of the BASIC assembler without any modifications! In other
words, although not their primary purpose, labels can be used in place of
data values in instructions.
@PRINT EOU$800C
LOA #0
@LOOP JSR @PRINT
ADDA #1
JMP @LOOP
END
The first instruction loads the A register with 0. The next three instructions
form a loop that prints the character corresponding to the ASCII code in
the A register, then adds one to the A register and so on. The result is that
every character that the Dragon can display is repeatedly printed on the
screen. You may be wondering what happens when the contents of the A
register reach 255 and you try to add one more to it? The answer is that lt
resets to zero and so the whole cycle repeats itself.
Summary
1 ) The main topics ofthis chapter have been the way the instructions
JMP, JSR and RTS are used to transfer control together with the
50
Chapter 4 Jumps, Loops and Labels
Micro Projects
1 ) Add subroutine6900 to print a list of all the labels used in a
program along with their corresponding addresses. Make sure that
the table is only printed at the very end of the second pass.
51
Chapter Five
Logic Instructions
This may sound like a very abstract and strange way of thinking about
things. Surely a bit pattern is always nothing more than a binary number?
The answer is, that while a bit pattern can always be interpreted as a
binary number, this is not always the best way to think about it. For
example, if you consider the contents of two memory locations as
numbers in the range O to $FF then it makes sense to consider arithmetic
operations, such as addition, on these numbers. However, suppose the bit
patterns stored in the two memory locations are being used to represent
characters, i.e. they are ASCII codes, then, although they can still be
interpreted as numbers, adding them together makes very little sense!
This lack of familiarity with the use of bit patterns doesn't make the
range of machine code operations any more difficult to understand; after
all, they are very simple operations. What is difficult is seeing how these
very simple operations can be put together to do anything useful. The
purpose of this and the next chapter is to explain the action of all of the
6809's operations on data. At this stage you may find that you understand
what the operations are doing, but not why you would ever want to use
some of them. For now, concentrate on gaining a rough idea of what the
52
Chapter 5 Logic Instructions
operations are all about and later on as you examine the examples and write
your own programs you will find that the use of each instruction will
become clear.
A B | A AND B
F F | F
F T | F
T F | F
T T | T
You should be able to work out the result of each line of the table using
nothing more than common sense. For example, if A is false and B is true
then the combined statement A ANO B is clearly false. In fact the
statement A AND B is only true if BOTH the statements A and B are true.
You probably already know that the above table is called a 'truth table'
and that all of the operations of logic can be summarised by similar truth
tables. The way that the logical operators of 6809 assembly language are
also best described by using truth tables. The only real change is that
instead of T and F they work in terms of 1 and 0 and on all the bits of a
memory location at once.
The 6809's AND, instruction in keeping with all of the other logical
instructions, will AND the contents of a memory location with the current
contents of the A or B register where it also leaves the result. The idea that
53
language of the Dragon
where reg. and mem. signify a bit in the appropriate register and in
memory respectively. The only extra complication is that the operation is
applied 'bitwise' to the two eight bit values. The meaning of 'bitwise' is
best explained by an example. If the A register contains $D5 and the
memory location contains $E7 then the result of AN Ding them together is -
A register 1 1 0 1 0 1 0 1
memory 1 1 1 0 1 1 1 0
result 1 1 0 0 0 1 0 0
or in other words, $C4. You can see that there is only a 1 in the result
when both the A register and the memory location contain a 1 in the same
place. This is because the result is obtained by applying the truth table to
each pair of corresponding bits i.e to the first bit in A and the first bit in the
memory location and so on.
Of the addressing modes that have been introduced so far, the ANDA
and ANDB instructions can be used with immediate, direct and extended.
So,
ANDA lf$34
and
ANDB $4020
are both legal examples.
54
Chapter 5 Logic Instructions
instruction, but they produce the bitwise OR of the current contents of the
A or B register and a memory location and leave the result in the register.
The only difference is that the truth table used is -
reg. mem. result
0 0 0
0 1 1
1 0 1
1 1 1
If you examine the table carefully you will see that the result is 1 if either of
reg. or mem. are 1. As an example of the OR instruction suppose that the
B register contains $E3 and the memory location contains $78. The result
would be -
B register 0 1
memory 0 0
result 0 1
or $FB. Notice that there is a 1 in the result wherever either value has a 1.
The ORA and ORB instructions support the immediate, direct and
extended addressing modes, so
ORB jl$F3
and
ORA $2950
are valid examples.
0 0 0
0 1 1
1 0 1
1 1 0
55
Language of the Dragon
Notice that the result is a 1 only when one of reg. or mem. is 1 . That is the
result is 1 if either but not BOTH is a 1 . As an example of the EOR
instruction suppose the A register contains $CE and the memory location
contains $5F then the result is •
A register 0
memory 0
result 0
or $91 . Notice that there is a 1 in the result only where there is exactly one
1 in either of the register or memory values. You can use all the addressing
modes that we have met so far (�ith the exception of inherent addressing)
with EDRA and EORB so
EDRA lf45
and
EDRA $A32A
re both valid examples.
COMA,
COMB and
COM address
56
Chapter 5 Logic Instructions
and this is applied bitwise as usual. For example, if the A register contains
$6F then the result of COMA is
register 1 1 1
result 0 0 0
or $90. The only addressing mode that can be used with COMA and
COMB is inherent and the BASIC assembler can already deal with this
mode.
The COM operation also has an extra form - COM address. This
instruction will perform the COM operation on the memory location given
by 'address'. This seems to invalidate an earlier fundamental observation
that for any operation to take place the data must be brought from
memory into the CPU. For example, COM $7F00 will complement the
contents of memory location $7 FOO without the intervention of the A or
the B register. In fact this 'direct' memory modification is nothing but an
illusion because the contents of the memory are brought into memory and
stored in a nameless temporary register, operated on and then restored
back in the original memory location. (This nameless register is of no great
interest from the programmer's point of view, in that you cannot use it in
any other situation, but it is nevertheless there). This apparent direct
modification of memory by the COM instruction is something that is
available as an extra with nearly all of the 6809's instructions that operate
only on a single data value. An example of the COM instruction is-
COM $7032
All that is needed to extend the BASIC assembler to handle the 6809's
complement of logical operations is the addition of the appropriate DATA
statements
57
Language of the Dragon
19 DATA ANDA,&H84,&H94,&HA4,&HBB,-1
20 DATA ANDB,&HC4,&HD4,&HE4,&HF4,-1
21 DATA DRA,&H8A,&H9A,&HAA,&HBA,-1
22 DATA ORB,&HCA,&HDA,&HEA,&HFA,-1
23 DATA EORA,&H88,&H98,&HA8,&HB8,-1
24 DATA EORB,&HC8,&HD8,&HE8,&HF8,-1
25 DATA COMA,-1,-1,-1 ,-1 ,&H43
26 DATA COMB,-1,-1 ,-1 ,-1,&H53
27 DATA COM,-1,&H03,&H63,&H73,-1
Bit manipulation
Setting any bit to zero is easy once you recall that the result of an AND
is only one if both of the corresponding bits in the register and memory are
1. Suppose the problem is to set b5 and b2 to zero in memory location
$7F00 which currently contains $36 -
b7 b6 b5 b4 b3 b2 b1 b0
0 0 1 1 0 1 1 0
(Notice that the bits in a memory location are numbered starting from
zero.) Then, ANDing the memory location with the bit pattern -
1 1 0 1 1 0 11
0 0 01 0 0 10
which is the same as the original contents of the memory location except
that b5 and b2 are 0 . If you look at the value that the memory location was
ANDed with then you should see that it is a sort of 'picture' of what we
58
Chapter 5 Logic Instructions
wanted to happen, in the sense that at each bit position where nothing
was to be changed there was a 1 and at each bit position to be zeroed
there was a 0 . For example, to zero b7 ,b5 and b1 you would AND the
contents of the memory location with
b7 b6 b5 b4 b3 b2 b1 b0
0 1 0 1 1 1 0 1
LDA$7 F00
ANDA *$5D
STA$7 F00
Notice the way that the A register is used to form the AND of the memory
location and the immediate data.
b7 b6 b5 b4 b3 b2 b1 bO
$54= 0 1 0 1 0 1 0 0
0 0 0 1 1 0 0 1
0 1 0 1 1 1 0 1
LDA$7FFO
ORA *$19
59
language of the Dragon
STA $7FF0
b7 b6 b5 b4 b3 b2 bl b0
1 0 1 0 0 1 0 1
011 0 1000
1 100 11 01
or $CD. The assembly language program to carry this out would be
LDA$7FF0
EORA ff,$68
STA$7FFO
You should be able to see that there is a pattern in these three ways of
manipulating bits. Each time the contents of a memory location are
combined using AND, OR or EOR with an immediate data with a particular
bit pattern. The immediate data is usually called a 'mask' and the rules for
construction and using a mask can be summarised as follows:
60
Chapter 5 Logic Instructions
b7 b6 b5 b4 b3 b2 b1 bO
1 1 0 0 0 0 1 1
b7 b6 b5 b4 b3 b2 b1 bO
1 <- 1 0 0 0 0 1 1 ? <-
As you can see the old value of b7 has 'fallen' off the end of the number
and there is a problem about what value should be 'shifted into' b0. There
are only two ways that shift instructions can vary -
61
Language of the Dragon
and, in the way that they solve the problem of what happens to b7 and
what value should be shifted into bO
It is worth keeping these two things in mind when reading the following
descriptions of the 6809's range of shift operations.
The characteristic that marks out the logical shift instructions is that the
bit that is shifted 'off the end' of the number is stored in a special register
inside the CPU and a O is shifted into the 'other end'. This special register
is called the condition code register and is fully described in the next
chapter. All that you need to know to understand how shift instructions
work is that a single bit of this register - the C or 'Carry bit' - is used to hold
the bit that would otherwise be lost as a result of the shift.
There are three forms of the LSL ( Logical Shift Left) instruction
LSLA
LSLB
and
LSL address
The first two perform the LSL operation on the A and B register
respectively and the third on the memory location at 'address'. The LSL
operation can be imagined as -
C - b7 b6 b5 b4 b3 b2 b1 bO - 0
indicating that all the bits are moved one place to the left, that b7 is shifted
into the C bit and a O is shifted into bO. For example, if the A register
contains $C5 or -
b7 b6 b5 b4 b3 b2 b1 bO
1 1 0 0 0 1 0 1
62
Chapter 5 Logic Instructions
C � � � M � � � �
1 1 0 0 0 1 0 1 0
or $8A with a 1 stored in the C bit. Notice that LSLA and LSLB are both
inherent but the direct and extended addressing modes can be used with
LSL address.
There are also three forms of the LSR (Logical Shift Right) instruction-
LSRA
LSRB
and
LSR address
The operation of the LSR instruction is roughly the same as the LSL
instruction except of course that all the bits are moved to the right. In this
case it is bO that is stored in the C bit and the O is shifted into b7. This is
best imagined as -
0--> b7 b6 b5 b4 b3 b2 bl b0 --> C
b7 b6 b5 b4 b3 b2 bl b0
1 1 o o o 1 o 1
� � � M � � � � C
0 1 1 0 0 0 1 0 1
or $62 with 1 stored in the C bit. All the other details of the LSR
instructions are the same as for the LSL instructions.
63
Language of the Dragon
1 0001 0 1 0
There are also three forms of the ROR ( ROtate Right) instruction
RORA
RORB
and
ROR address
64
Chapter 5 Logic Instructions
which apply the ROR operation to the A register, the B register and the
memory location at 'address' respectively. The ROR instruction works in
the same way as ROL only the bits are moved to the right. The best way to
think of the R()R operation is -
b7 b6 b5 b4 b3 b2 b1 b0
1 1 0 0 0 1 0 1
and the C bit is 1 the result of RORA is -
1 11 0001 0
or $E2 and the new value of the C bit is 1 .
The key feature of the ROL and ROR instructions is that they both
involve the current value of the C bit. So far the only way that we have of
determining the C bit is via the use of the shift instructions themselves.
Instructions to change the C bit directly are discussed in the next chapter
and these make the ROR and ROL instructions much more useful.
The 6809 does have another shift instruction but this is also better
described as part of the next chapter, on arithmetic.
65
Language of the Dragon
30 DATA LSL,-1,&H08,&H68,&H78,-1
31 DATA LSRA,-1 ,-1 ,-1 ,-1,&H44
32 DATA LSRB,-1,-1 ,-1 ,-1 , &H54
33 DATA LSR,-1 , &H04,&H64,&H74,-1
34 DATA ROLA,-1,-1 ,-1 ,-1 , &H49
35 DATA ROLB,-1 ,-1 ,-1,-1,&H59
36 DATA ROL,-1 , &H09,&H69,&H79,-1
37 DATA RORA,-1,-1,-1,-1 ,&H46
38 DATA RORB,-1,-1 ,-1 ,-1 ,&H56
39 DATA ROR,-1 , &H06,&H66,&H76,-1
In the last chapter the idea of using a label to represent an address was
introduced. It may not have been clear from the description that an
address label can be used anywhere that an address can. In particular, as
well as being used in JMP instructions to specify the 'destination' address
labels can be used to specify the location of data in operations such as
AND etc. For example, suppose you are using memory location $7FF0 to
store some data, then to load it into the A register you could use-
LDA $7FF0
but perhaps -
@DATAEQU$7 FF0
LDA@DATA
ln short, labels are just as useful when used to represent the addresses of
data as destination addresses in JMP instructions. However, it is very
important to preserve the distinction between immediate addressing and
extended addressing. For example
66
Chapter 5 Logic Instructions
LDA !f@LABEL
will load the A register with the value of @LABEL and
LDA @LABEL
will load the A register with the value stored in the memory location whose
address is the value of @LABEL.
This idea of using labels for data is worth extending by the use of three
new pseudo ops - RMB (Reserve Memory Bytes), FCB (Form Constant
Byte) and FOB (Form Double Byte). When a label is used as a destination
address it isn't defined using the pseudo op EQU, instead it is defined by
the position that it occupies in the program - i.e. by the instruction that it
labels. This idea can be used to define labels that 'mark' memory locations
used to store data. For example, suppose you want to use three memory
locations to store some information and you don't really mind exactly
where they are as long as they are out of the way of the program and you
know exactly where to find them. The RMB pseudo op can be used to
reserve any number of memory locations anywhere in a program. For
example,
LDA@DATA
ANDA jf$0F
JMP @LOOP
@DATA RMB3
the RMB instruction reserves 3 memory locations for data storage at the
end of the program and the label @DATA is equal to the address of the
first of them. The effect of-
label RMB n
is simply to reserve the next n memory locations for data and set the value
of the label to the address of the first one. In many ways RMB looks just
like a standard machine code instruction that takes n memory locations to
store!
RMB is useful for reserving memory (for large tables, for example) but
often in a program it would be an advantage to define a single memory
location as holding data and also initialise it to some value. This is exactly
what the FCB pseudo-op does -
@DATA1 FCB $76
67
Language of the Dragon
FCB stores $76 in the next free memory location and sets the label
@DATA1 to its address. It is important to be clear that FCB is not an
instruction that the 6809 carries out - after all it is a pseudo-op, an
instruction to the assembler to do something. What happens when the
assembler meets
is that it stores 'value' in the next memory location (i.e. the one that it
would have used to store the machine code of the next instruction) and
sets 'label' to its address. When the assembled machine code program is
run, the only effect that the FCB has had is that memory location 'label'
contains 'value'. The pseudo-op FOB works in more or less the same way
as FCB except that it uses two memory locations to store its value and the
label is set to the address of the first of the two memory locations.
68
Chapter 5 Logic Instructions
6620 POKE P ,A
6630 P = P + l
6640 RETURN
Lines 4002-4004 detect the new pseudo-ops and set the variable PS to a
value that indicates which one has been found. Lines 6540-6560 process
RMB, the only effect of which is to increase the value of P by the number
of memory locations to be reserved. Notice that any label used with RMB
(or FCB and FOB) will be processed in the normal way, just as if the new
pseudo-ops were standard mnemonics and the 'value' that follows the
pseudo-ops will be processed as an address field and stored in the variable
A. Lines 6570-6640 process an FCB pseudo-op. The only point to notice
here is that the value POKEd into memory is truncated by line 6580 to be in
the range O - 255. In other words, an fcb like FCB $1234 will be interpreted
by the assembler as FCB $34. Lines 6650-6720 process a PDB pseudo-op.
This is done in much the same way as for the FCB, only now two values
are POKEd into memory HB, and LB representing the 'high' or 'most
significant' byte and the 'low' or 'least significant' byte of the value
respectively. Quite a few of the statements in the pseudo-op handler look
complicated but are simply formatting and printing the results of the
assembly so that you can keep track of what is going on.
If you are a little unsure of the way that RMB, FCB and FOB are used
then you will find plenty of examples in forthcoming chapters!
Summary
1 I The logicaloperators AND, OR, EOR and COM have been
described in this chapter along with the logical shifts LSL, LSR, ROR
69
Language of rhe Dragon
2) The idea that the 'bit pattern' is the fundamental type of data that
assembly language programs work with has been emphasised by a
discussion of bit manipulation using the logical operators.
3 ) Finally the use of labels to mark the location of data was intro
duced along with the pseudo-ops RMB, FCB and FOB.
Micro Projects
1) Some information is stored in an memory location labelled by @DATA.
Write a short program that will set b6 to 1 and b3, b2 and bl to O without
affecting any other bits.
3) How could you use LSL and ROL to move the top four bits in the A
register into the bottom four bits in the B register? (In other words b7, b6,
b5 and b4 of the A register should occupy b3, b2,b1 and bO respectively of
the B register.)
4) Write a program which defines two memory locations as data using the
FCB pseudo-op and then ANDs their contents together placing the result
in yet another memory location.
70
Chapter Six
Arithmetic Instructions
This chapter examines the ways in whiCh the6809 can handle bit patterns that
represent numbers. It is important that you are clear about the way that
numbers can be represented by bit patterns and what sorts of things can go
wrong with seemingly simple arithmetic. Fortunately there is no need to
understand and actually be able to do binary arithmetic because the 6809 can
do it for you! As you read this chapter, try to keep in the back of your mind that
the fundamental data for assembly language programming is the bit pattern
and everything else, including numbers, is a result of the way that you are
using bit patterns.
The use of the ADDA and ADDB instructions to add two numbers together
has already been described in earlier chapters. However, there is more to 6809
assembly language arithmetic than these two instructions. In particular, there
is the question of working with numbers larger than $FF and that of working
with negative numbers. Before these and other aspects of arithmetic are
explained it is worth explaining the role that arithmetic plays in assembly
language programming. It is probably true to say that in BASIC, arithmetic is
basic! But this is not so in assembler. It takes many assembly language
instructions to perform the apparently simple sum
2.321 / 1 .422
that BASIC would accept in one go or even as part of another instruction! The
result of the high level of difficulty encountered with assembly language
arithmetic is that complex calculations are rarely found in assembly language
programs. If you are planning to write a program that needs much in the way
of calculation, then it is better to think in terms of BASIC or a mixture of
71
Language of the Dragon
assembly language and BASIC. If you really do need the undoubted speed
advantage of assembler in doing complicated calculations than you will need
to use a very special collection of assembly language subroutines called a
'software floating point package'. In most cases, however, the sort of
application that assembly language is put to only needs the addition,
subtraction and occasionally multiplication of fairly small numbers and this is
not so difficult.
So far the only sort of numbers that we have been able to deal with are
positive numbers in the range O to $FF. There is more than one way to
represent a negative number in binary but the most common and the one
used by the operations in the 6809 is the so-called 'two's complement form'.
There is an extensive theory behind two's complement negative numbers but
all that you need to know to use the negative numbers in assembly language is
their format.
If you ask yourself what makes a number like -6 a negative number, the
answer is that ·if you add it to + 6 the answer is 0. That is to say, the
fundamental property that makes a number negative is that, if x is a number
then its negative, i.e. -x, is a number that when added to x gives the answer
zero. This definition of a negative number seems to be interesting but hardly
useful until you recall an observation made in Chapter Four. If you add one to
a memory location or a register you will eventually reach the maximum value
that can be stored, i.e. $FF. The question is what happens if you add one to
this maximum value? The answer is not that you get an error message,
instead the result is zero.
72
Chapter 6 Arithmetic Instructions
Now you should be able to see how negative numbers can be represented
in binary in such a way that they play their correct part in arithmetic. Instead of
using the whole range O to 255 as representing positive numbers the range is
divided into two halves, the positive numbers from O to 127 and the 'negative'
numbers from 128 to 256. This representation of negative numbers as the
second half of the total range is known as 'two's complement
representation'. Its single great advantage is that if you use it you can carry
out any arithmetic that you like without worrying about whether a number is
positive or negative - that aspect looks after itself! Notice that this isn't true of
the usual decimal way of handling negative numbers. For example, if you do
the sum 3 +4, then you add the two numbers; but the sum 3 + (-4) would be
done by subtraction. In binary, both sums would be done using addition, the
first 3 +4 in the usual way but 3 + (-4) would be done by finding the two's
complement of 4 and then ADDING it to 3.
You needn't worry about the details of carrying out arithmetic in two's
complement form because the 6809 will look after you, but you do need to
know the essential features of a two's complement number. Any number
between O and $7F (0 - 127 in decimal) is a regarded as a positive number.
Putting this another way, any binary number that has b7 equal to O is regarded
asa positive number. Any number between $80 and $FF (128 -255 in decimal)
is regarded as a negative number. Putting this another way, any binary
number that has b7 equal to 1 is regarded as a negative number. Thus, if you
are using two's complement arithmetic all you have to do to decide if a
number is positive or negative is to look at b7 - if it's O then the number is
positive, if it's 1 then the number is negative. For example,
b7 b6 b5 b4 b3 b2 bl bO
0 1 0 1 1 0 0 0
b7 b6 b5 b4 b3 b2 bl b0
1 0 1 1 0 1 0 1
73
Language of the Dragon
ADDD address
adds the contents of the memory locations at 'address' and at 'address + 1' to
the current contents of the D register, leaving the result in the D register.
Notice that two memory locations are used to store the value that is added to
the D register and, in line with the way that extended addresses are stored,
the most significant eight bits are stored in 'address' and the least significant
eight in 'address'+ 1. In the case of the D register, the A register holds the
eight most significant bits and the B register holds the eight least significant
bits. These two facts can be illustrated thus -
74
Chapter 6 Arithmetic Instructions
ADDD *$FE72
The ADD and SUB instructions can be used to carry out arithmetic on
simple binary numbers as long as the result is in the same range as the original
numbers. For example,
LDA *$0A
ADDA *$06
will correctly add $0A to $06 leaving the result $10 in the A register or ·
LDA *$0A
SUBA *$06
which will correctly subtract $06 from $0A leaving the result $04 in the A
register. You can carry out any arithmetic with the A register as long as the
numbers are in the range O to $FF and get a correct answer as long as the
result is also in this range. If the result is outside this range then the 'roll over'
75
Language of the Dragon
LDA jl$F0
ADDA jl$1 5
leaves the result 5 i n the A register which i s certainly not correct and
LDA jl$06
SUBA jl$07
leaves the result $FF in the A register which once again is far from correct.
When performing arithmetic on bit patterns that you are considering as
simple binary numbers, the rule is that the result must be in the same range as
the original numbers. For arithmetic on the A and 8 registers the range is O to
$FF and for the D register the range isO to $FFFF. Notice in particular this rules
out any negative results for, after all, negative numbers are no part of simple
binary!
You may be worried about the possibility of carrying out some arithmetic in
a program and using invalid results because of overflow. This problem will be
dealt with in the next chapter where instructions that can be used to test for
overflow will be described.
The rule for carrying out arithmetic with two's complement numbers is the
same as for simple binary numbers in that the result must lie in the same range
as the numbers involved in the arithmetic. The main difference is that, of
course, now we can work with negative numbers and get negative results.
For example,
LDA jl$06
SUBA jl$07
gives the result $FF which is the two's complement form of -1, which is
correct. Notice that the result is only correct because we are working with
two's complement numbers. You might be thinking that this distinction
between two's complement and simple binary is something that can be
76
Chapter 6 Arithmetic Instructions
ignored until you get a negative result. However, if you are using two's
complement representation
LDA jl$FF
ADDA jl$05
has to interpreted as adding $FF or-1 to $05 which when you take the roll over
into count give the answer $04 which is quite correct. However, if you
interpret the numbers as simple binary then the answer is the same, i.e. $05,
but it isn't the correct answer to $FF+ $05! Once again the point is that the
arithmetic is the same no matter what the bit patterns represent but the
meaning of the answer depends on whether you are using simple binary or
two's complement. You can still get an overflow while using two's
complement if the result is outside the range of numbers that can be
represented. How to detect a two's complement overflow will be described in
the next chapter.
NEGA
NEGB
and
NEG 'address'
which will perform the NEG operation on the A register, the B register and the
contents of the memory location at 'address' respectively. (Notice that there
is NO NEGD instruction.) The NEG operation changes a two's complement
positive number into a two's complement negative number. For example,
LDA jl$01
NEGA
results in $FF in the A register which is of course the two's complement
representation of-1. One of the most useful facts about the NEG operation is
that it will not only change a positive number into a negative number but vice
versa. This is rather like the familiar -(-3) giving the result 3. For example,
LDA jl$FF
NEGA
77
Language of the Dragon
results in $01 in the A register. So, using NEG you can easily convert between
positive and negative numbers.
To summarise -
CLRA
CLRB
and
CLR 'address'
which perform the CLR operation on the A register, the 8 register or the
contents of the memory location at 'address' respectively. The CLR operation
is simplicity itself, it loads the register or the memory location with O (i.e. eight
zeros).
78
Chapter 6 Arithmetic Instructions
and
INC 'address'
which perform the INC operation on the A register, the B register and the
memory location at 'address' respectively. The INC operation simply adds
one to the register or the memory location.
DECA
DECB
and
DEC 'address'
which performs the DEC operation on the A register, the B register and the
memory location at 'address' respectively. The DEC operation, as you might
suspect, subtracts one from the contents of the register or memory location.
These three operations CLR, INC and DEC are faster and take less memory
than their equivalents and are nearly always to be preferred.
Adding the instructions that have been introduced so far is mainly a matter
of including the appropriate DATA statements. The one exception is the
introduction of the operations on the D register that allow immediate
addressing i.e. LDD,ADDD and SUBD. Currently the BASIC assembler can
only handle eight-bit immediate addressing. All that has to be done to cope
with the possibility of 1 6-bit immediate data is to test for the presence of "D"
at the end of an instruction and then POKE two memory locations, the first
79
Language of the Dragon
with the most significant byte and the second with the least significant byte of
the value of the address field.
40 DATA ADDD,&HC3,&HD3,&HE3,&HF3,-1
41 DATA SUBA,&H80,&H90,&HA0,&HB0,-1
42 DATA SUBB,&HC0,&HD0,&HE0,&HF0,-1
43 DATA SUBD,&H83,&H93,&HA0,&HB0,-1
44 ATA CLRA,-1 ,-1 ,-1 ,-1 ,&H4F
45 DATA CLRB,-1 ,-1 ,-1 ,-1 ,&H5F
46 DATA CLR,-1 ,&H0F,&H6F,&H7F,-1
47 DATA INCA,-1 ,-1 ,-1 ,-1 ,&H4C
48 DATA INCB,-1 ,-1 ,-1,-1 ,&H5C
49 DATA INC,-1 ,&H0C,&H6C,&H7C,-1
50 DATA DECA,-1 ,-1 ,-1 ,-1 ,&H4A
51 DATA DECB,·1 ,-1 ,-1,-1 ,&H5A
52 DATA DEC,- 1 , &H0A,&H6A,&H7A,-1
53 DATA NEGA,-1 ,-1 ,·1 ,-1 ,&H40
54 DATA NEGB,-1 ,-1 ,-1,-1 ,&H50
55 DATA NEG,-1,&H00,&H60,&H70,-1
56 DATA STD,-1,&HDD,&HED,&HFD,-1
57 DATA LDD,-1,&HCC,&HDC,&HEC,&HFC,-1
The only line that needs any explanation is 6024 which checks for a "D" at the
end of the mnemonic in immediate mode i.e. when TYP E = 1. If this is
detected, TYPE is changed to 4 so that two memory locations will be POK Ed
with the value in A (see line 6040 in the existing program).
So far, the only arithmetic that has been described in detail is eight-bit
simple or eight-bit two's complement arithmetic using the A and B registers.
As already briefly discussed, you can use the A and B registers together - as
the D register - but the range of operations on the D register is rather limited.
However, the D register is the simplest way of carrying out 1 6-bit arithmetic.
If you use the 16 bits to represent only positive numbers i.e. simple binary
80
Chapter 6 Arithmetic Instructions
then you can cope with a range of O to 65535. If you use 1 6-bit two's
complement then the range is -32768 to + 32767 In either case the range is
often large enough not to have to worry about extending it any further. For
example, if you want to add two numbers that are too large to be represented
in eight bits but are within the 1 6-bit range then -
LDD @NUM1
ADDD @NUM2
STD @NUM3
where @NUMl , @NUM2 and @NUM3 each label the first of TWO memory
locations that hold the 1 6-bit numbers. Subtraction can be achieved by
replacing the ADDO @NUM2 instruction by SUBD @NUM2 instruction. All
the comments about overflow and two's complement form apply to
arithmetic on the D register if you take into account the much increased
range. So for example, $FFFF is the1 6-bittwo's complement representation
of -1 (because adding 1 to $FFFF makes it 'roll over' to 0).
The lack of a NEGD instruction makes it a little difficult to obtain the two's
complement form of a number. This little problem is easy to solve once you
recall that 0-x is -x. So to obtain the two's complement of a 1 6-bit number
use-
LOO fi,O
SUBD@NUM
where @NUM labels the first of two memory locations that holds the value.
LDB@SMALL
CLRA
ADDD @LARGE
STD @ANS
81
Language of the Dragon
where @SMALL labels a single memory location holding the eight-bit value,
@LARGE labels the first of two memory locations holding the 16-bit value
and @ANS labels the first of two memory locations used to store the 1 6-bit
result. You could subtract the two numbers simply by changing the ADDO
@LARGE to SUBD @LARGE. This method works for simple binary numbers
because, to change an eight-bit value into, a 16-bit value all you have to do is
write eight zeros in front. However, things are not so simple for negative
two's complement numbers. For example, $FF is eight-bit two's complement
for -1 but adding eight zeros in front gives $0 0 FF which is 1 6-bit two's
complement for 255. The correct thing to do is to add eight ON ES to the front
of a negative two's complement number. For example, writing eight ones in
front of $FF gives $FFFF which is the1 6-bit two's complement representation
of -1 . Obviously, for positive two's complement numbers the correct thing to
do is to write eight zeros in front of the number and so it looks as though
extending two's complement eight-bit to 16 bits is difficult. Once again the
6809 comes to our rescue- this time with the SEX (Sign EXtend) instruction.
If you load the B register with an eight-bit two's complement number and
than use the SEX instruction the A register will be loaded with eight zeros if
the number in B is positive and eight ones if the number is negative, correctly
extending the number. So, the two's complement equivalent of the previous
eight-bit/1 6-bit addition is -
LDB @SMALL
SEX
ADDD@LARGE
STD@ANS
where the labels have the same meaning as before. Notice that if the values to
be added were simple binary then using SEX to set the A register would give
you an incorrect answer - so take care and think about which representation
you are using.
Going back the other way, that is from 16 bits to eight bits, is also easy. If
you are using simple binary then obviously if the result of an operation leaves
the A register with nothing in it then you can ignore it and use the contents of
the B register as a correct eight-bit result. In other words, taking eight zero
bits off the front of a 1'6-bit number converts it into an eight-bit number. For
example·, $0 032 is the sameas$32 but $0132 is not the same as $32. For two's
82
ChBpter 6 Arithmetic Instructions
The logical shifts were introduced in the last chapter and the arithmetic
shifts work in a similar way but their purpose is very different. If you are using
a bit pattern to represent a simple binary number then shifting the pattern one
place to the left is the same as multiplying the number by 2 and shifting it one
place to the right is the same as dividing it by 2 and ignoring any fractional
part. (Compare this to what happens to a decimal number when you multiply
it by 10 or divide it by 10 . 1 This means that LSL and LSR can be used to
multiply and divide by 2. For example, if the A register contains $0A (1 0 in
decimal) or
b7 b6 b5 b4 b3 b2 bl bO
0 0 0 0 1 0 1 0
83
Language of the Dragon
000 1 0 1 00
00000 1 0 1
or $05.
This use of the logical shifts is fine for simple binary numbers but when it
comes to two's complement representation, things start going wrong. If you
shift a negative two's complement number to the right using a LSR then a O is
shifted into b7, which changes the number from negative to positive and this
is not what is supposed to happen when dividing by 2. For example, if the
number in the A regi�ter is $86 {which represents -122),
b7 b6 b5 b4 b3 b2 b1 b0
1 0 0 0 0 1 1 0
0 1 0000 1 1
or $43 (which represents + 67). The correct answer to-122 divided by2 is-61
or in two's complement -
1 1 0000 1 1
If you compare this number against the original you will see that to get the
correct answer only needs a 1 to be shifted into b7 when the right shift is
performed. However, this is not the whole answer because always shifting a1
into b7 would give the wrong result when the number was positive. The
correct solution is to perform the right shift in such a way that b7 keeps its
value. This is the essence of an ASR (Arithmetic Shift Right) operation. The
ASR operation is available in the usual three forms -
84
Chapter 6 Arithmetic Instructions
ASRA
ASRB
and
ASA 'address'
which perform the ASA operation on the A register, the B register and the
contents of the memory location at 'address' respectively. The ASA
operation is can be thought of as -
--> - b7 b6 b5 b4 b3 b2 bl bO --> - C
I I
I I
-< ---
in other words, all the bits move one place to the right, bO is stored in the C bit
and b7 retains its current value.
b7 b6 b5 b4 b3 b2 bl b0
0 0 1 0 0 0 0 0
then following a ASLA instruction the A register contains -
0 1 000000
or $40 which is twice $20. However, following a second ASLA the A register
contains -
1 0000000
or $80 which is the two's complement representation for -128 which is
definitely not twice $40 ( + 64 in decimal).
85
Language of the Dragon
You may be wondering what all the fuss about multiplying and dividing by
two is. The answer is that you can often multiply by small constants using
nothing but shifts and adds. For example, to multiply the contents of a
memory location by 5 you could multiply by 2 twice and then add the original
number to the result i.e. if a is the number 5a = 4a + a. Converting this to a
program (assuming that the memory location to be multiplied is at $7FOO)
gives-
LDA$7F00
ASLA
ASLA
ADDA$7F00
STA$7F00
This program will multiply the contents of $7 FOO but it is hardly complete in
the sense that it makes no checks for an invalid result due to overflow: to do
this would need instructions introduced in the next chapter!
For the general multiplication of two simple binary numbers the 6809
provides the MUL instruction. The MUL instruction multiplies the two simple
binary numbers in the A and B registers and leaves the result in the D register.
As the largest result that this can produce is $FFFF there is no chance of any
sort of overflow and there is nothing that can go wrong when using the MUL
instruction. For example, if the A register contains $0A (10 in decimal) and the
B register contains $52 (82 in decimal) then following a MUL instruction the D
register contains $0334 (820 in decimal). Notice that the MUL instruction will
only give the correct answer if the two numbers to be multiplied together are
in simple binary. In other words you can only directly multiply together
positive numbers using MUL.
86
Chapter 6 Arithmetic Instructions
The basic idea behind the BCD representation of a number is that using
four bits you can represent the decimal digits O to 9 (using simple binary).
Using this idea a number such as 2389 can be written as
2 3 8 9
001000111000 1001
lr. other words each digit of the number is coded separately in binary as a
group of four bits. This means that a single eight-bit memory location can be
i.Jsed to store a BCD number in the range O to 99 which should be compared to
the range of a simple eight-bit binary number i.e. 0 to 256. P It should be
obvious that you cannot add two BCD numbers and get the correct answer in
BCD using the standard ADD instruction. To make BCD arithmetic easier the
6809 provides that DAA ( Decimal Adjust Al instruction. This instruction is a
little different from all the other instructions that we have looked at so far in
that it does nothing useful when used on its own. To be of any use the DAA
instruction has to used in conjunction with the ADD instruction. Indeed it is
probably better to think of the pair of instructions -
ADDA address
DAA
1 I 2
0001 I 0010
o I s
00001 1001
LDA 4f $1 2
ADDA 4f$0A
87
Language of the Dragon
gives the result $1 C which is not the correct answer in BCD. However,
following a
DAA
2 I 1
0010 10001
58 DATA SEX,-1,-1,-1,-1,&Hl D
59 DATA ASRA,-1,-1,-1,-1,&H47
60 DATA ASRB,-1,-1,-1,-1,&H57
61 DATA ASR,-1,&H07,&H67,&H77,-1
62 DATA ASLA,-1,-1,-1,-1,&H48
63 DATA ASLB,-1,-1,-1 ,-1,&H58
64 DATA ASL,-1,&H08,&H68,&H78,-1
65 DATA MUL,-1,-1,-1,-1,&HJD
66 DATA DAA,-1,-1,-1,-1,&H19
Summary
1 l There are three common ways of using bit patterns to represent
numbers -
i) simple binary - for positive numbers
ii) two's complement - for negative and positive numbers
iii) BCD - for doing decimal-like arithmetic
88
Chapter 6 Arithmetic Instructions
for eight bits0 to 255 - represented by $00 to $FF for 1 6 bits0 to 65535 -
represented by $0000 to $FFFF .FI .IN 0 .IN 5
4) A single memory location can hold two BCD digits giving a range
of 0 to 99.
7) Finally BCD addition can be carried out two digits at a time using
the instruction pair ADDA, DAA.
Micro projects
1 ) Write a short program that will add together a pair of eight-bit
simple binary numbers. Assume that the first number is stored in
@DATAl, the second in @DATA2 and that the result has to be
stored in @ANS. Would your program be capable of adding together
200 and 50?
89
Language of the Dragon
90
Chapter Seven
Branch Instructions
As these program forms are so important, you may be wondering why they
have been left so until such a late chapter for discussion. The reason is that all
the conditional branches make use of another register in the 6809 - the CC or
'Condition Code' register - that records certain facts about the result of the
last operation. This is simple enough. The complication is that these factsare
always recorded but whether they make any sense or not depends on what
you are using the bit patterns to represent. For example, the CC register
records whether or not the last result was negative or positive but this
information is only meaningful if you are working with two's complement
numbers. For this reason, a consideration of the conditional branches have
been left until you have made the acquaintance of not only simple binary but
two's complement and BCD representations as well. It is possible to use the
branch instructions without worrying about the subtleties of what the bit
pattern is representing but sooner or later such an approach will lead you to
make a programming error that you have little chance of finding! The branch
group of instructions are best treated as a special group by the BASIC
assembler because they all use a new addressing mode, 'relative addressing',
which is also described in this chapter.
91
Language of the Dragon
The 6809 has two instruction BR/\ (BRAnch) and LBRA (Long BRanchl
that seem to do the same job as the JMP instruction in that they both transfer
control to an instruction at a specified address. However, the way that the
address is specified in a BRA or LBRA instruction is different and has certain
advantages over the addressing modes that can be used with the JMP
instruction. The addressing mode used with the BRA and LBRA instructions
is known as 'relative addressing'. The form of the BRA instruction is -
BRA offset
M + 2-128 up to M + 2 + 127
As M + 2 is the start of the next instruction and the range of an eight-bit two's
complement number is-128 to + 127. Thus you cannot transfer control to any
memory location using the BRA instruction. You might think that only being
able to reach memory locations roughly 100 locations higher and lower than
the position of the BRA instruction would be so restricting that the JMP
92
Chapter 7 Branch Instructions
_H...____
0
destination
address PC + offset
Start of _.. PC
next instruction
offset
$20 BRA
memory
93
Language of the Dragon
LBRA offset
where the machine code for LBRA is $ 1 6 and the offset occupies two memory
locations in the standard two's complement format. Once again, the
destination address is obtained by adding the offset to the address of the next
instruction. The only difference is that the LBRA instruction takes up three
memory locations and the offset is a 1 6-bit two's complement number. This
makes the addressing range of the LBRA instruction
M + 3-32768 up to M + 3 + 3 2767
94
Chapter 7 Branch Instructions
DATA mnemonic, code for eight-bit relative, code for 16-bit relative
and this has the added advantage of being very similar to the format of the
branch table in Appendix I. Once a branch instruction has been detected then
all that has to be done is to read through the table of other instructions until
the Zl.Z. that marks the end is encountered and then search though the branch
table, remembering to use the new format for the DATA statements.
1 REM BASIC ASSEMBLER V7.1
400 DATA BRA,&H20,&H16
499 DATA ZZZ,-1 ,-1
4009 IF (LEFT$(M$,1 ) = "B" AND LEFT$(M$,3)< > "BIT") OR
LEFT$(M$,2) = "LB" THEN GOT04500
4500 READC$
4510 FOR K = l TO5:READC(K):NEXT K
4520 IFC$< > "ZZZ"THEN GOTO4500
4530 IF LEFT$(M$, 1) = "L" THEN M$= RIGHT$(M$,3):BR =2 ELSE
BR = l
4535 TYPE= BR
4540 READC$
4550 FORK = 1 TO2:READC(K):NEXTK
4560 IFC$= "ZZZ"THENI = I + 1 :ER = 1 :RETURN
4570 IFC$ = M$THENRETURN
4580 GOTO 4540
95
Language of the Dragon
Lines 400 and 499 are the only DATA statements in the branch list so far (499
marks the end of the list with llZ). Line4009 detects the the mnemonic is one
of the branch group and passes control to the routine at 4500 to 4580. This
routine first skips over the rest of the instruction table and then reads the
branch table to find the matching mnemonic. Line 4530 test to see if the
instruction is a branch or a long branch. If it is a long branch then the L is
removed from the front of the mnemonic and BR is set to 2. If it is a normal
branch then BR is set to 1. The variable TYPE is then set to the same value as
BR, because once the matching mnemonic in the table is found the code for a
branch will be in C(1) and for a long branch in C(2). It should be noticed that
this doesn't imply any connection between relative addressing and address
modes corresponding to TYPE= 1 and TYPE =2 (immediate and direct) it is
simply a programming convenience.
BRA @LOOP
LBRA $BF00
are perfectly correct assembly language. To a certain extent, this normal use
of addresses hides the fact that BRA and LBRA are using relative addressing.
However, you will soon be reminded of the fact if, for example, @LOOP is too
far away to be reached by an eight-bit offset!
The modification to the BASIC assembler has to convert the address value
in A to a relative address if the instruction is a branch. Detecting that the
address field belongs to a branch instruction is simply a matter of testing the
variable BR for a value greater than O (BR= 1 is a branch, BR =2 is a long
branch). Converting the address to relative form is a little more complicated.
If the branch is to transfer control to the address stored in A and the address at
96
Chapter 7 Branch Instructions
which the branch instruction will be stored is in P, then the offset can be
calculated using -
OF = A - 2 - P
OF = A - 3 - P
Recalling that the value of BR for branches and long branches is 1 and 2
respectively, you should be able to see that the offset is equal to -
OF = A - BR - 1 -P
in both cases. If the offset turns out to be positive then there is nohing else to
be done apart from POKEing 1 memory location for an eight- bit relative
address and 2 memory locations for a 1 6-bit relative address. If the offset is
negative then it has to be converted to the correct two's complement form
before being POKEd into memory. For an eight-bit relative address this can be
done by -
256-0F
65536-0F
97
Language of the Dragon
5750 RETURN
5760 A = 65536-OF
5770 RETURN
Line 5024 detects a branch instruction and hence a relative address and
transfers control to a new routine at 5700. This calculates the offset, including
conversion to two's complement if necessary, as described earlier. Line 5710
checks that an eight-bit relative address is in the correct range.
This idea of looking back at the result of the last operation to decide the
outcome of a branch instruction is perhaps easier to appreciate once you
know how it works. The CC or Condition Code register has already been
mentioned in earlier chapters as the place where the C or Carry bit is stored. In
fact it is an eight bit register in which each of the bits has a special name and a
special function. For example, one of the bits in the CC register, b2, is called
the Z or Zero bit and this is set to 1 if the result of the last operation was zero
and a 0 otherwise. Notice that the Z bit, like the C bit, is changed by the
98
Chapter 7 Branch Instructions
previous operations even if it is not going to be used in anyway later on. In this
sense the CC register really does monitor the 'condition' of the 6809 by
continually recording information about previous results.
Not all of the eight condition bits within the CC register are of interest to us
at this stage. Of the eight bits only five are concerned with the outcomes of
operations on data and so only these five are described below:
b7 b6 b5 b4 b3 b2 b1 bO
. . H . N Z V C
where '.' indicates that the purpose of the bit will be described in Chapter Ten.
The H bit
The H or Half carry bit is used by the DAA instruction to do BCD arithmetic.
(See Chapter Six). Normally this bit isn't of any direct interest or use to the
assembly language programmer. The best policy is to accept that the DAA
instruction uses it and then forget about it.
The N bit
The N or Negative bit is always equal to b7 of the last result. Obviously if
you are working with simple binary numbers all that the N bit will indicate is
whether or not the last result was equal to or bigger than $80 and this is not
very useful. However, if you are working with two's complement numbers,
b7 is 1 if the number is negative and O if it is positive. Thus for two's
complement numbers the N bit indicates whether or not the last result was
negative or not.
The Z bit
The Z or Zero bit has already been discussed briefly. It is 1 if the previous
result was zero and O otherwise.
99
Language of the Dragon
The V bit
The V or overflow bit is the most complicated of all the condition code bits.
It is 1 if the last operation caused a two's complement overflow and 0
otherwise. Of course if you are not using the two's complement
representation then the V bit's value makes no sense at all!
The C bit
The C or Carry bit has already been described in Chapters Five and Six in
connection with the logical and arithmetic shift operations. Its most common
use is as a carry or borrow in multiple precision arithmetic and this is explained
fully in Chapter Eight. However, it is also used to test for overflow in simple
binary arithmetic and as a way of discovering the value of the bit shifted out as
a result of a shift instruction. In its role as a carry bit used to detect overflow it
is best thought of as a ninth bit produced as a result of an eight-bit addition or
subtraction. You should be able to see that following simple eight-bit binary
arithmetic the C bit should.be 0 if the result can be represented in eight bits. In
the same way it can be thought of as a 17th bit as a result of 1 6-bit addition or
subtraction. Once again if the result can be correctly represented in 1 6 bits
there should be no carry and the C bit should be 0.
Notice that the four condition code bits N, Z, V and C that are used by the
conditional branches fall into two groups. The N and Z bits both reflect a
property of a single number or bit pattern - i.e. is it negative or zero
respectively. However, the V and C bits reflect an aspect of the result of an
operation - i.e that an overflow or a carry occurred. For this and various other
reasons, not every instruction changes all, or even any, of the condition
codes. It is obviously very important to knbw which of the condition code bits
any given instruction will change but to fist each one here would take too
much space. A complete list of which bits each instruction affects is given as
part of Appendix I and this should be used for reference. Fortunately, it is
usually easy to work out which instructions do and do not change the
condition codes. For example, instructions which load registers set the N and
Z bits so that tests can be made on the value loaded. The C bit is left unaltered
lit is difficult to see how a 'carry' can arise when you are not doing any
arithmetic!) and the V bit is zeroed because no overflow has occurred.
However, until you are familiar with 6809 assembler the best policy is to look
up in Appendix I which condition codes are affected by the instructions prior
to making use of the condition codes.
1 00
Chapter 7 Branch Instructions
There are two instructions that allow the assembly language programmer
to alter the condition code register directly - ANDCC and ORCC. Both
instructions can only be used with immediate addressing and the action of -
ANDCC jldata
is to form the AND of the current contents of the CC register and the eight bit
value 'data' leaving the result in the CC register. The action of
ORCC jldata
is to form the OR or the current contents of the CC register and the eight bit
value 'data' leaving the result in the CC register. If you followed the discussion
of bit manipulation in Chapter Five you will realise that AN DCC and ORCC
allow you to set any bit in the CC register to either O or 1 without affecting the
current state of any of the other bits. For example, if you want to set the C bit
to zero (sometimes referred to as 'clearing the carry') then use-
ANDCC jl$FE
ORCC jl$01
Although you can change any of the bits in the CC registE!r in practice it is only
the C bit that is ever changed directly in this way. Generally before any ROL or
ROR instruction the C bit should be initialised to either O or 1 as appropriate.
(This is also the case when using multiple precision arithmetic with the ADC
and SBC instructions to be explained in Chapter Eight.)
101
Language of the Dragon
The signed conditional branch instructions that are used with two's
complement numbers.
The unsigned conditional branches that are used with simple binary
numbers.
Each of these instructions can only be used with eight-bit relative addressing.
If the destination address is outside the range of eight-bit relative addressing
then each of the simple branch instructions is available in a long branch form,
e.g. BPL is also available as LBPL ( Long Branch Positive).
The way that each of the above simple conditional branches behaves is
easy enough to understand. What is not so clear is that way that each one
might be used as part of a program. It is perhaps worth dealing with each pair
in turn.
102
Chapter 7 Branch lnsrructions
LDA jl$05
SUBA jl$08
BMl @MINUS
the branch to @MINUS will be taken because the result of the subtraction is
negative. Notice that as far as BPL and BMI are concerned O is a positive
number. Of course, there is nothing stopping you from using BPL and BMI
when the numbers involved in the arithmetic are simple binary. Howev_er, the
interpretation of the branch as a test for positive and negative numbers then
becomes a nonsense. There is one problem that can occur with the use of
BPL and BMI. If during the course of a two's complement calculation the
result becomes invalid due to an overflow, the BMI or BPL will still be selected
according to the value of b7 of the result but this result may not be what you
expect it to be. In other words, it is possible to take a correct branch from an
incorrect answer! For example, consider -
LDA jl$7F
ADDA jl$2
BPL@PLUS
$7F is the two's complement representation of1 27. Adding $2 to this should
give the result 129 and so the BPL should transfer control to @PLUS.
However, 1 29 is outside the positive range of an eight-bit two's complement
number and so the result is actually $81 which is the two's complement
representation of -1 28 and the branch to @PLUS is therefore not taken and
control passes to whatever instruction follows the BPL. This problem of
branching or not branching on an invalid result is a problem to be found in
other branch instructions.
103
Language of the Dragon
understand this is that a BEO will be taken if all eight bits of the results bit
pattern are 0 . This all 0 pattern can arise in a number of ways. For example, if
the bit patterns are being used as two's complement numbers then -
LOA Jl$10
SUB Jl$10
BEQ@ZERO
The result of the SUB instruction is $0 and so the BEO transfers control to
@ZERO. A less obvious example is -
LDA Jl$FO
ANDA Jl$0 F
BEQ @ZERO
The result of AN Ding $FO with $OF is $00 and so the branch to @ZERO is
taken.
LOA Jl$7F
ADDA Jl$0 2
BVS @ERROR
104
Chapter 7 Branch Instructions
LOA 1f$FE
ADDA 1f$02
BCS @ERROR
results in the branch to @ERROR being taken because $FE added to $02 gives
the result $01 and a carry. There are other uses for BCC and BCS apart from
detecting simple binary overflow. By using LSL and LSR instructions it is
possible to shift any bit into the C bit and then use the BCS and BCC
instruction to take a branch depending on whether the bit was 0 or 1 . By
detecting simple binary overflow following a subtract instruction it is possible
to tell that the value in the register was less than the value in the memory- but
more of this later.
LDA 1f$50
SUBA 1f$24
BGT @BIGGER
105
Language of the Dragon
The branch to @BIGGER is taken because $50 is greater than $24. (In this
case r, the value in the register, is$50 and m, the value in the memory, is$24.)
This is all there is to using the signed conditional branches.
If you subtract two numbers, one stored in a register and one in memory (or
immediate data) then you can use any of the above branch instructions as
long as you remember to interpret the numbers as two's complement
numbers. You might think that two's complement overflow might be a
problem with the signed conditional branches. In other words, do the signed
branches work when a two's complement subtraction results in an invalid
result? The surprising answer is that they do! Even when the result of the
subtraction is invalid, i.e. a BVS is taken indicating an overflow, the signed
conditional branches still work correctly. The reason for this is that the signed
conditional branches can deduce the sign that the correct result would have
had if it could have been worked out correctly! Consider, for example-
LDA jl$80
SUBA jl$01
BLE @SMALL
In this case the result of the subtraction should be -129 (because $80 is -128 in
two's complement and subtracting 1 gives -129). However, because -1 29 is
outside the range of representation of eight-bit two's complement arithmetic,
the result is actually $7F or + 127 which is incorrect (and the V bit is 1 to
indicate overflow) but the branch to @SMALLis correctly 1-128 is less than 11
taken. It is worth remembering that (and trying to understand why) the signed
conditional branches will work even IT the result of the subtract is invalid.
The unsigned conditional branches are the simple binary equivalents of the
signed conditional branches. In other words they can be used to compare two
simple binary values. The unsigned conditional branches are -
106
Chapter 7 Branch Instructions
r> = m BHS-Branch
Higher or Same BLO-Branch LOwer
r= m BEG-Branch EOual BNE-Branch Not Equal
Once again the branch instruction have to follow a subtract operation. r is the
numbers stored in the register and rn is the number stored in the memory
location (or immediate data), for example -
LDA lf$80
SUBA lf$7F
BHl @HIGHER
In simple binary $80 is 128 and $7 F is 127 so the result is 1 and the contents of
the register are larger or higher than the memory location and hence the
branch to @HIGHER is taken. In the same way that the signed conditional
branches will branch correctly on an invalid result so will the unsigned
conditional branches. Consider, for example -
LDA lf$7F
SUBA lf$80
BLO @LOWER
The result of 127 minus 128 is -1 and this cannot be represented in simple
binary (no negative number can be represented in simple binary!) but even
though the result is incorrect ($FF) the branch to @LOWER is still correctly
taken.
It is worth pointing out that BLO is identical to the BCS instruction and the
BHS instruction is identical to the BCC instruction. The additional
mnemonics BLO and BHS are used mainly for convenience and to distinguish
the uses of the BCS and BCC instruction that are concerned with testing the
value of bit shifted into the carry during logical shifts etc and applications of the C
bit that involve arithmetic. It is important not to confuse the signed and
unsigned conditional branches. If you are using two's complement
representation, i.e. if you are using negative numbers, then use the signed
107
Language of rhe Dragon
conditional branches. If you are not using negative numbers then you are free
to choose a simple binary representation and the unsigned conditional
branches.
108
Chapter 7 Branch Instructions
41 5 DATA BSR,&H8D,&H17
416 DATA BVC,&H28,&H1028
417 DATA BVS,&H29,&H1029
SUBA 1\$10
BEQ @LOOP
109
La�guage of the Dragon
result of the subtraction, and it might be that if A isn't equal to $10 then the
current value is used by later parts of the program. One solution would be to
save the A register before the subtraction and re-load it with its old value after
the subtraction and the branch but this is a very inefficient way of comparing
two values.
The correct solution is to use the CMP instruction which will carry out the
subtraction and set the condition codes in exactly the same way as a SUB
command but will not save the result. In other words, following a CMPA
#$10 command the condition codes are set as if $10 had been subtracted
from the A register but the contents of the A register are left unchanged. Now
the problem of comparing two numbers is completely solved and the previous
example can be written -
CMPA #$10
BEQ @ LOOP
The branch will be taken if the A register is equal to $10 but the contents of the
A register remain unaltered no matter what happens.
The CMP instruction has another advantage over the SUB instruction in
that it is available as
CMPA address
CMPB address
and
CMPD address
The final form allows you to compare the contents of the D register (see
Chapter Six) with a 16-bit value and branch on the result. For example-
CMPD #$0172
BLT @LESS
will take the branch to @LESS if the contents of D are less than $0172 in two's
complement representation.
110
Chapter 7 Branch Instructions
TSTA
and
TSTB
which have the same effect (but take less memory) than
CMPA 1\0
and
CMPB 1\0
TST address
effectively subtracts zero from the memory location at address and sets the
condition code bits accordingly. TST can be used with direct and extended
addressing.
In the same way that the CMP operation performs a subtraction without
altering the contents of the register involved, the BIT (Bit Test) instruction
performs the AND operation with out changing the register. A typical
application of the BIT instruction is to discover when two bit patterns,
whatever they represent, are the same or not. For example, suppose you
wanted to know if the value stored in the A register had b4 set to 1 irrespective
of the setting of the other bits. Then you could use -
11 1
Language of the Dragon
BITA lf$10
BNE @SET
because the result of AN Ding anything with $10 can only be non-zero if b4 is
set to 1 - try it! As with the CMP instruction, following BITA the contents of
the A register are unchanged. The BIT instruction has only tw_o forms-
BITA address
and
BITB address
Adding CMP and BIT to the BASIC assembler is simply a matter of adding
their DATA statements and this has already been done in V7 .2 given above.
112
Chapter 7 Branch Instructions
The only form of the IF statement that has an easy translation into assembly
language is IF condition THEN GOTO where the 'condition' is a simple
relation between two values. For example, the BASIC -
LDA @ANS
CMPA @CONST
BGT @SKIP
where @ANS and @CONST are memory locations holding the two values to
be compared and @SKIP labels an instruction further down the program.
Notice that as BGT has been used the assumption is that the two values are
two's complement numbers in the range-128 to +127. If boh values cannot
become negative then the positive range could be extended to + 255 but the
branch instruction would then have to be changed to BHI @SKIP. Once
again it is important to be clear what the bit patterns are being used to
represent.
10 COUNT = 0
20 COUNT = COUNT+ 1 0
30 IF COUNT=1 0 0 THEN GOTO 1 0 0 0
40 GOTO20
is a simple conditional loop that adds 10 to COUNT until it is equal to1 0 0 . The
assembly language equivalent of this would be -
113
Language of the Dragon
CLRA
@LOOP ADDA lf$0A
CMPA lf$94
BEQ @FINISH
BRA @LOOP
Notice the way that the BRA instruction is used to form a loop in the same
way that a GOTO would be in BASIC. Also notice that as the BEO instruction
works with any representation the form of the program remains the same
even if you are working with two's complement numbers. In this case 1 00 is
outside the range of eight-bit two's complement numbers so a simple binary
representation is used.
FOR 1 = 1 TO 1 0
. . .
NEXT I
is
LDB lf$01
@FOR1 'other
assembly
language'
. . .
INCB
CMPB lf$0A
BLE @ FOR 1
This form of the assembly language FOR loop can be modified to include a
negative step by changing INCB to DECB and to allow for STEP sizes larger
than 1 by using ADDB lf@STEP. For all its flexibility, however, the needs of
assembly language programming can often be met by something a lot simpler
than this. Very often all that is required is to repeat a section of program a
number of times. For example, suppose you wanted to shift the contents of
the A register to the left four times you could use -
114
Chapter 7 Branch Instructions
LOB J!$04
@ LOOP LSLA
DECB
BNE@LOOP
The way that this works is to load the B register with the number of times you
want to repeat the instruction inside the loop and then DECrement the B
register each time through. When the contents of the B register reach O the
BNE is not taken and the loop ends. Notice that using this method of counting
down to O there is no need to use a CMP instruction to discover when the loop
is at an end because the Z bit is automatically set by the DEC instruction.
Summary
3) The branch instructions come in two forms, the branches and the
long branches using eight and 16-bit relative addressing respectively.
The conditional branches fall into three groups-
1 15
Language of the Dragon
Micro projects
1) Using ANDCC and ORCC set the 2 bit to 1 and the C bit to 0.
116
Chapter Eight
11 7
Language of the Dragon
detailed explanation of the whole program, a table giving the purpose of each
subroutine"is given at the end of the listing.
5 CLEAR 2000,&H6FFF
2000 CLS
2010 PRINT@66," B A S I C A S S E M B L E R "
2020 PRINT
2030 PRINTTAB(lO); "SELECT ONE OF"
2040 PRINT
2050 PRINTTAB(8); "INPUT/EDIT ......1 "
2060 PRINTTAB(8I; "ASSEMBLE........2"
2070 PRINTTAB(8); "SAVE ONTAPE....3"
2080 PRINTTAB(S); "LOAD FROMTAPE..4"
2090 PRINTTAB(S); "EXECPROGRAM....5"
2100 INPUT ACTION
21 1 0 IF ACTION< 1 ORACTION>5THEN GOT02000
2120 0N ACTION GOTO 2200,2800,2850,2920 ,2990
2200 CLS
2210 PRINT@76,"E D I T"
2220 PRINT
2230 PRINTTAB(l O); "SELECT ONEOF"
2240 PRINT
2250 PRINTTAB(8);"LIST PROGRAM....1 "
2260 PRINTTAB(8);"LISTTO PRINTER.2"
2270 PRINTTAB(S);"ADDTOPROGRAM.. 3"
2280 PRINTTAB(8);"DELETE LINES ... .4"
2290 INPUTED
118
Chapter 8 Using the Dragon from Assembler
2400 GLS
2405 IFI = 0THENGOTO1 980
2410 FOR K = l TOI
2420 IF ED = 1 THEN PRINT K;":";TABl4);A$IK) ELSE
PRIN T jj,-2,K;":";TAB(4);A$(K)
2430 NEXTK
2440 GOTO 1 980
119
Language of the Dragon
120
Chapter 8 Using the Dragon from Assembler
routine purpose
1 980-1990 press any key to continue entry to 2000
2000-2120 main menu and selection
1 21
Language of the Dragon
The assembler's new facilities mean that you can type in a program, list
it, insert and append new lines to it and delete incorrect lines from it. You
can also save and load programs to tape. As assembly language errors are
very often destructive it is a good idea always to save a program before
trying it out. Other features should be self-explanatory when you come to
use the assembler.
122
Chapter 8 Using the Dragon from Assembler
The problem of separating the two groups of 4 bits is easy to solve using the
AND operation and shifting. What about converting a simple 4 bit binary
number tothe correctASCII character? Fortunately theASCll codesfrom0-9
and A-F run in sequence but there is a 'gap' between9 and A. To see what this
means examine the following table
1010 A 01000001
1011 B 0 1 000010
1 100 C 0 1 000011
1101 D 0 1 000100
1 1 10 E 01000 1 0 1
1111 F 01000110
For a value in the range 0 to 9 you can convert the 4 bit binary to its
corresponding ASCII code by adding 00 1 1 000 or$30. lfyou examine the table
for values greater than 9 you should be able to see that the 4 bit value can be
converted to the corresponding ASCII code by adding $37 (this is simply the
difference between the two codes).
Armed with this information the program-is now fairly easy to write-
123
language of the Dragon
LSRA
BSR @HPRN
LDA @TEMP
ANDA jl$0F
BSR @HPRN
RTS
The first part of the program, starting at @HEX performs four left shifts to
move the top for bits b7�b4 down into b3·b0. Notice that, by using LSRA,
zeros are shifted into the top four bits. After this subroutine @HPRN is called
to print the ASCII character corresponding to these four bits. The bottom 4
bits are then isolated by the ANDA jl$0F which sets the top four bits to 0
leaving the rest unaltered (see bit manipulation · Chapter Five). Then
subroutine @HPRN is called again to print the second four bits in hex. The
only thing left to describe is the action of subroutine @HPRN. This first tests
to see if the value in the A register is greater than 9. If it isn't it adds $30 and
uses subroutine @PRINT to print the ASCII character on the screen. lf it is
bigger than 9 then $37 is added and @PRINT is used to print the ASCII
character on the screen.
Even in this simple program there are a number of subtle points. Notice the
way that the task of adding the correct value to the four bits is implemented as
a subroutine so that it can be used more than once. The principle of using
subroutines as often as possible applies just as much to assembly language
programming as to BASIC. Also notice the way that the jump to the 'internal'
subroutine @HPRN is achieved using a BSR and to the 'external' subroutine
using JSR. This is such good 6809 assembly language practice that it is worth
getting used to early on but exactly why it is such a good idea will have to wait
1 24
Chaprer 8 Using the Dragon from Assembler
until Chapter Eleven. The branch instruction BHI is used because the four·bit
numbers might as well be considered to be simple binary although, with the
limited range of O to 15, two's complement could just as easily be used.
@START CLRB
@LOOP BSR @HEX
LOA jl$20
JSR @PRINT
INCB
BRA @LOOP
This should be typed in before the @HEX subroutine and EXECuted. You will
see the screen fill with pairs of hex digits faster than you can read! The JSR
@PRINT in the main program print a space (ASCII $20) between each pair of
hex digits.
0 to 4,294,967,296
125
Language of the Dragon
-2,147,483,648 to + 2 ,147,483,647
using two's complement, it is possible that you might want to use even more
memory locations to increase the range. This is quite easy once you have seen
the general principle behind extended arithmetic. In practice it is this rather
more complicated subroutine that is of practical use but it will have to wait for
the next chapter to be completed,
Most
significant Least significant
1st @HNUM1 @LNUM1
2nd @HNUM2 @LNUM2
then the first thing to do is add the two least significant eight bits together by-
LOA @LNUM1
ADDA @LNUM2
This produces the correct answer for the least significant byte of the answer
but, if the values stored in @LNUM1 and @LNUM2 are large enough, the
correct answer may be so large that it needs nine bits to represent it. If you
look back to the description of the C or Carry bit in Chapter Seven you will see
that it is used to store the 'overflow' from any arithmetic. After adding
together the least significant bytes and storing the result, the next stage is to
add the most significant bytes of the pair of numbers. The only difficulty is
that any 'carry' produced from the adding the least significant bytes should
also be added into the result. The 6809 has two extra arithmetic operations
that will perform addition or subtraction, taking into account any carry from a
previous operation - ADC (ADd with Carry) and SBC (SuBtract with Carry).
Both ADC and SBC work in roughly the same way as the familiar ADD and
SUB instruction in that they leave the result of the operation in the register.
The only real difference is that ADC and SBC take account of any carry from a
previous operation and there is no ADCD nor SBCD operation. To add the
two instructions to the BASIC assembler .include the following four DATA
statements -
126
Chapter 8 Using the Dragon from Assembler
77 DATA ADCA,&H89,&H99,&HA9,&HB9,-1
78 DATA ADCB,&HC9,&HD9,&HE9,&HF9,-1
79 DATA SBCA,&H82,&H92,&HA2,&HB2,-1
80 DATA SBCB,&HC2,&HD2,&HE2,&HF2,-1
The final program for adding the pair of 16-bit numbers together is
LOA @LNUM1
ADDA @LNUM2
STA @LANS
LOA @HNUM1
ADCA @HNUM2
STA @HANS
which stores the most significant byte of the answer in @HANS and the least
significant byte in @LANS.
The program for adding numbers taking four memory locations is just as
simple if rather �onger,
LOA @1NUM1
ADDA @1NUM2
STA @1ANS
LOA @2NUM1
ADCA @2NUM2
STA @2ANS
LOA @3NUM1
ADCA @3NUM2
STA @3ANS
LOA @4NUM1
ADCA @4NUM2
STA @4ANS
127
Language of the Dragon
SBCA. Notice that the first add or subtract in each of these programs ignores
the carry bit.
It is possible to write a general program that will add and subtract any
number of memory locations but this requires yet a little more assembly
language and it is covered in the next chapter. The problem is that to operate
on a variable number of memory locations requires some way of keeping track
of the all the addresses. The idea of using labels such as @1 NUM1 to
@1 NUM4 is all very well for four memory locations, but imagine trying to use
the same method for 10 or 20 memory locations!
The program that is the subject of this section plays the familiar video game
of squash. It is far from a finished game in the sense that it doesn't include
scoring or any sort of 'user friendliness'. However, it is a complete program
from the point of view of the essential working parts of the game. The ball, a
square block, bounces around the screen. A small bat can be moved to the
right and left using the left and right arrow keys and the ball will bounce off it if
it happens to be in the correct position at the correct time. The most
important thing about the program, however, is that it is an excellent example
of assembly language arithmetic in action and of the way in which a larger
assembly language program is put together.
Rather than tackle the problem in one go it is easier to approach the finished
program in three main stages ·
Bouncing a 'ball'
The techniques involved in bouncing a ball around the Dragon's text screen
should be well known to you from BASIC. ( For general information about the
principles involved consult Chapter Six of "The Complete Programmer"
published by Granada.) The idea is to keep a record of the ball's position in
two variables X and Y. These are updated by adding the current values of two
other variables XV and YV i.e.
128
Chapter 8 Using the Dragon from Assembler
Xnew = Xold + XV
Ynew = Yold + YV
Perhaps the best way to illustrate the methods employed in bouncing a ball
around the screen is to give a BASIC program. This not only shows how
things work, it provides a model for the assembly language program and will
give you a good idea of the speed advantage inherent in assembler.
20 YCORD = 0
3 0 XVEL= 1
40 YVEL= 1
50 C$ = CHR$I128I
60 GOSUB1000
70 C$ = " "
80 GOSUB1000
90 GOSUB2000
100 GOTO50
129
Language of the Dragon
Subroutine 1000 prints the character stored in C$. Subroutine 2000 updates
the X and Y values and checks for a possible 'collision' with the edge of the
screen! If a collision is detected then the appropriate velocity is reversed.
Notice that the velocities are either 1 or -1 for simplicity.
(For the details of this equa�ion see "The Anatomy of the Dragon", also
published by Sigma.) Before this expression can be implemented in
assembler it is necessary to decide on a suitable representation for XCORD
andYCORD. The possible range forXCORD isO to31 andforYCORD O to 1 5.
Both of these values can easily be stored in a single memory location using
simple binary as there is no possibility of a negative number ever occurring.
However, as the address calculated by the above expression is a 1 6-bit
quantity we must be prepared to combine eight-bit values and 1 6-bit
arithmetic (see Chapter Six). Also, as the velocities are going to have to vary
between 1 and -1 , two's complement arithmetic is going to enter into the
program somewhere. So, assuming that @XCORD and @YCORD label
single memory locations used to hold the ball's co-ordinates and @CHAR
labels a single memory location holding the character code character to be
'printed', the subroutine to calculate the screen memory location is -
The first part of the program multiplies the value in @YCORD by 32. This is
achieved using five shift lefts. The calculation starts off using eight-bit
arithmetic but, as the final answer is going to be 16 bits, the A register is
cleared to produce a valid 1 6-bit number in the D register. Since the value lies
in the range O to 1q, i.e. it is held in the first four bits, there is no chance of an
overflow for the first four shifts but the fifth shift could produce a number
outside the range of eight-bit simple binary representation. If you look back at
the definition of ASL you will see that b7 is shifted into the C bit and so, if the
fifth shift causes an overflow it will be in the C bit. The question is how to
move this C bit into the A register. This can be achieved using the ROLA
instruction which shifts the C bit into bO of the A register which is just what we
want. So multiplication by 32 can be achieved by five ASLB instructions
followed by one ROLA, leaving a valid simple binary number in the D register.
The next part of the program adds the @XCORD value. As this is an eight-bit
value it has to be added to the D register in a round about way. First, the least
significant bytes are added using ADDB @XCORD. This may produce a carry
which then has to be added to the most significant byte in the A register. This
is done using an ADCA #$00 instruction. To understand this just ask yourself
what the eight most significant bits of @XCORD are - the answer is eight
zeros. Adding Zero to take account of the carry is something that is often
encountered in eight-bit/16-bit register arithmetic. Now that @XCORD has
been added, the only operation left is the addition of $400 to give the final
address. As this is a constant there is no trouble about representing it as a
16-bit simple binary value and adding it to the D register using ADDO
Jl$0 40 0 .
The reason why this piece o f arithmetic was s o complicated is that the
values involved in the calculation were mainly best represented as eight-bit
quantities but the answer has to be a 16-bit quantity. This mixing of the
number of bits couldn't have been completely avoided even by representing
all the values as 16-bit values- there is no 16-bit shift - and the alternative way
of multiplying by 32 using the MUL instruction uses eight-bit values in the A
and 8 registers. In most assembly language programming there is no avoiding
this sort of 'mixed precision arithmetic'.
At the end of this routine we have in the D register the address of the screen
memory location in which the character code has to be stored. The question
now is what to do with it? So far we have no way of storing a value in a
131
Language of the Dragon
memory location whose address has been worked out in the course of a
program. What we need is the facility to say 'use the number stored in a
register as the address of a memory location'. The 6809 does provided this
facility as a separate addressing mode called 'indexed addressing'. Indexed
addressing is in fact a whole family of addressing modes and for this reason it
is given a whole chapter - the next one - to itself! However, one form of
indexed addressing is so useful that its introduction cannot be postponed any
longer.
The 6809 has another register called the X register that is a full 16 bits in
length and can be used to hold an address. It can be loaded and stored using
the instructions LDX and STX in much the same way that the D register can.
However, it is different from the D register in that it isn't used to do
calculations. It is primarily an 'addressing' or 'pointer' register. That is, it is
used to hold the address of the memory location that another instruction will
operate on. For example, the instruction -
STA ,X
will store the contents of the A register in the memory location whose address
is stored in the X register. Don't worry for the moment about the "," in front of
the X. All it is used for at this stage is to alert the assembler to the fact that
indexed addressing is being used.
Now we have the solution to what to do with the address of the screen
location left in the D register -
STD @SCREEN
LDX @SCREEN
LDA @CHAR
STA ,x
RTS
The first two instructions transfer the contents of the D register to the X
register by way of the pair of memory locations labelled by @SCREEN (a
more direct way to do this will be introduced in the next chapter). The next
instruction loads the A register with the character code and the STA ,X stores
this value into the screen memory location whose address is in X. Finally RTS
completes the @DRAW subroutine.
1 32
Chapter 8 Using the Dragon from Assembler
The next subroutine that is required it the subroutine that updates the
co-ordinates and changes the velocities when there is a collision. The
@UPDATE subroutine is another exercise in assembly language arithmetic
but this time with the added interest of using conditional branches to test the
results. The subroutine is best thought of in two parts -
133
Language of the Dragon
@YCORD and @YVEL. As these two halves are so similar, only the first half
will be described. All of the arithmetic in this subroutine can be carried out in
eight bits using the A register. The contents of @XCORD are added to
@XVEL and then stored back into @XCORD. The only thing to notice here is
that @XVEL could be negative (i.e. -1 1 and so @XCORD could decrease in
value. The BNE checks for a zero result. If one is found the @XVEL has its
sign changed using the NEG instruction. Notice that there is no need to use
CMPA #0 because the condition code bits are set by the STA instruction. To
check for the other extreme value, however, it is necessary to use CMP #31 .
Once again, however, a BNE instruction is used to skip round the NEG
@XVEL instruction. The second half of the program updates @YCORD and
@YVEL in roughly the same way.
All that now remains is to write the main program that uses the
subroutines-
This works in the same way that the BASIC main program given earlier did.
The program is in the form of a loop and each time through the @UPDATE
subroutine is used to move the ball and the @DRAW subroutine is used
twice, once to display the ball and once to print a blank to remove it. If you
were to put the main program together with the subroutines and EXEC the
program you would see the ball bounce around the screen very fast. The only
trouble is that at the moment the BASIC assembler cannot handle the
instructions LDX and STA ,X.
134
Chapter 8 Using the Dragon from Assembler
The simplest way to add indexing to the BASIC assembler is to test for a H, H
in the address field and then set TYPE = 3 as a result. There are a few other
matters to be cleared up but the changes are not at all difficult-
81 DATA LDX,&H8E,&H9E,&HAE,&HBE,-1
5800TYPE=3
581 0 AF$ = "&H84"
5820 RETURN
Subroutine 5800 will eventually be expanded to cope with the job of coding
other varieties of indexed addressing.
Now that the BASIC assembler can handle the indexed addressing mode
used in @DRAW the whole program can be typed in and tested. Remember
to include all of the two subroutines following the main program. Once you
have entered the program correctly you can EXECute it and see the results,
You might be a little disappointed at what you see as the ball zips about the
screen a little too fast! In fact it zips about the screen so fast that it is difficult to
see the whole ball at any given moment. The solution to this problem is to
include a delay subroutine between the first and second uses of the @DRAW
135
Language of the Dragon
The bat is made up from three solid blocks and its position on the screen is
controlled using the x co-ordinate of the leftmost block (see fig 8. 1). The
problem of drawing the bat is considerably eased by the fact that it only
moves horizontally. If the x co-ordinate of the lefthand block of the bat is
stored in @XBAT, then the address of the corresponding screen memory
location is -
where 'base' is the address of the screen memory location on the far left of the
same line that thebatison. lfthebatistobe printed on line 14, base is equal to
$05CO. The subroutine to draw the bat at @XBAT is -
136
Chapter 8 Using the Dragon from Assembler
•
@XBAT {+11 { + 21
137
Language of the Dragon
The way that this program works is straightforward, in that it first calculates
the address of the screen location corresponding to the left hand block of the
bat and then stores the character code in @CHAR in it, but as the bat consists
of three blocks, it then has to store the same character code at
@ADDRESS + 1 and @ADDRESS + 2. This it achieves by using the D
register to add one to the contents of @ADDRESS and then using it in the X
register to govern where the contents of the A register are stored. This is a
rather long way of storing something in three consecutive memory locations.
There is a more concise way of achieving the same ends and this will be
described in the next chapter.
All that is needed now is a second subroutine to update the bat's position
depending on which of the two arrow keys is pressed. The update procedure
is simple. If the left arrow key is pressed then @XBAT should be decreased by
one and if the right arrow key is pressed @XBAT should be increased by one.
There are a number of extra considerations apart from just moving the bat
that make the update subroutine just a little more complicated than this. In
the first place it is important to make sure that the bat doesn't go off the edges
of the screen and in the second it would be easier to play the game if the
keyboard had a fast auto-repeat feature. The first requirement merely
involves checking that the value in @XBAT is greater than O before
subtracting one from it and less than 29 before adding one to it. The
auto-repeat facility is also easy to produce once you know that the Dragon
maintains a table of keys pressed at $1 50 to $1 59 and the way to fool it into
thinking that a new key has been pressed is to store $FF in each of these
locations. In fact, as a press of either arrow key is recorded in memory
locations $1 51 , $157 and $158 these are all that have to be set to $FF in this
case. The update subroutine is -
138
Chaprer 8 Using rhe Dragon from Assembler
JNC @XBAT
@REPKEYLDA jf$FF
STA @ROLL
STA @ROLL2
STA @ROLL3
RTS
@ROLL EQU $151
@ROLL2 EQU $157
@ROLL3 EQU $158
@KEYB EQU $8006
The first instruction uses the machine code subroutine @KEYB to read the
keyboard. This subroutine returns the ASCII code of any key pressed in the A
register or returns zero if no key is pressed. If no key is pressed the second
instruction transfers control to the end of the @UPBAT subroutine. The rest
of the subroutine checks for a left or right arrow key press and only updates
@XBA T if it is in the correct range. The last part of the subroutine, starting at
@REPKEY implements the auto-repeat key described earlier.
All that is now required is a new version of the main program given earlier.
@START BSR @UPDATE
LBSR @UPBAT
LOA lf$80
STA @CHAR
BSR @DRAW
BSR @DBAT
BSR @DELAY
LOA jf$8F
STA @CHAR
BSR @DRAW
BSR @DBAT
BRA @START
@XCORD FCB 0
@YCORD FCB 0
@XVEL FCB 1
@YVEL FCB 1
@CHAR FCB 0
@ADD
RESS FOB 0
@XBAT FCB 12
1 39
Language of the Dragon
This is the final part of the. squash program, consisting of a single new
subroutine to detect the ball hitting the bat and to act upon it. There are a
number of ways that the ball colliding with the bat could be detected but the
most instructive from the point of view of assembler is by comparing the
- 3 ball positions
"BAT
140
Chapter 8 Using the Dragon from Assembler
co-ordinates. If the ball is in contact with the bat it can be in any one of the
three positions shown in fig 8.2. This implies that you can detect when the ball
should be bounced from the bat by the following condition -
and
To express this another way, to detect a bounce the subroutine has to test
that the difference between @XCORD and @XBAT lies in the range O to 2:
If the @YCORD of the ball is just one line above the bat (as shown in fig 8.2)
then the x co-ordinates are checked. This is done by subtracting them. If the
result is negative then the difference is less than zero so a bounce cannot
occur. If the difference if positive it is compared to 2, once again if it is greater
a bounce cannot occur. If the co-ordinates do satisfy all the conditions the the
bounce is implemented simply by reversing @YVEL.
141
Language of the Dragon
To make sure that you get everything in the right place the output of the
BASIC assembler for the squash program is given below -
142
Chapter 8 Using the Dragon from Assembler
143
Language of the Dragon
144
Chapter 8 Using the Dragon from Assembler
Conclusion
In this chapter you have seen the way that a large assembly language
program is built up from subroutines. You should now have the flavour of
assembly language programming and if you have typed in and tried the
squash program an idea of some of the difficulties and rewards. The BASIC
assembler is working at its limits to assemble a program of over 100 lines and
fortunately the examples in the rest of the book do not approach this length I It
should now be clear that if you are going to use assembler at all often you
should purchase a good, fast assembler. Study the squash program until you
understand what each part is doing. To check that you do understand try
taking it a little further, add a routine to make the ball go out of play if you miss
it, a score line and so on.
145
Chapter Nine
146
Chapter 9 The addressing registers · indexed addressing
There are five registers within the 6809 that are exclusively concerned with
the matter of specifying address�s. Four of them are full addressing registers,
in the sense that they are 16 bits long and able to hold a complete address, and
one of them, the DPor 'Direct Page' register, is only eight bits long and has to
be used in conjunction with other information to determine a full address. In
fact the OP register is so different and special that it is better to treat it in a
section all on its own towards the end of this chapter. The four full addressing
or 'pointer registers' are called the X, Y, U and S registers. Although all four of
them can be used in the same way as far as index addressing goes, the X and
Y registers are a little more limited than the U and S registers. In particular, the
U and S registers are involved in so-called 'stack operations' which are
explained in the next chapter. Also the S register is used by the 6809 to keep
track of return addresses during subroutine calls and returns. For this reason
the X and Y registers are called the 'index registers' and the U and S registers
are called the 'stack pointers'. Despite the different names used for the
registers, it is important to realise that as far as indexed addressing is
concerned the four registers are identical. However, even though they are
identical in theory, the Dragon uses the S register extensively and it is safer to
use the index registers for indexing and the stack registers mainly for stack
operations, as described in the next chapter.
Although the pointer registers are used for a different purpose to the A and
B registers there are a number of operations that they share with them. For
example, in the same way that you can load and store the A and B registers
using LOA, LOB, STA and STB you can load and store the pointer registers
using similar instructions e.g. LOX loads the X register. Because they are so
similar to the already familiar A and B register operations, rather than treat
each of the operations on the pointer registers at length, it should be
sufficient to list them:
147
Language of the Dragon
LDS address
LDU address
LDX address
LDY address
STS address
STU address
STX address
STY address
CMPS address
CMPU address
CMPX address
CMPY address
Simple indexing
1 48
Chapter 9 The addressing registers - indexed addressing
LDA,X
loads the A register from the memory location whose address is stored in the
X register. Similarly,
STA ,U
stores the contents of the A register in the memory location whose address is
stored in the U register.
You may be wondering what the comma in front of the register's name is
for. The answer is that you can write a number in the range -32768 to32767 in
front of the comma that will automatically be added to the contents of the
register and the result used as the address of the memory location. For
example, if the X register contains $6000 the instruction
LDA 3,X
will load the A register from $6003. The number to the left of the comma is
known as the 'offset' because, rather like the offset used in relative
addressing, it indicates how far away, in terms of memory locations, the data
is from the address currently in one of the pointer registers. So the general
form of 'simple' or 'constant offset indexing' as it is more properly called is -
It is important to realise the contents of the pointer isn't altered in any way
by being used in indexed addressing. For example, LOA 1 , X only adds 1 to X
to work out the address to be used. The contents of X after the instruction are
the same as they were before the instruction. In other words, the address
calculation only produces a temporary result.
149
Language of the Dragon
The address is calculated in the same way and then transferred to the X
register using @ADDRESS as an intermediary. Then the A register is loaded
from @CHAR and stored in the three consecutive memory locations given by
X, X + 1 and X + 2. If you compare both versions of the subroutine you will
immediately see that indexed addressing not only makes the program
shorter, it also makes it easier to understand. The subroutine would be even
shorter and easier to understand if there was some way of transferring the
contents of the D register directly into the X register. There is indeed an
instruction that will transfer the contents of any register to any other.
TFR r1,r2
will transfer the contents of register rl into register r2 without altering the
contents of r1. For example,
150
Chapter 9 The addressing registers - indexed addressing
TFR A,B
results in the contents of the A register also being stored in the B register. (In
other words, both registers now contain the same value.) The instruction-
EXG r1,r2
is superficially like the TFR instruction but it transfers the contents of register
r1 into register r2 AND it also transfers the original contents of r2 into r1. That
is, it swaps the contents of the registers. For example,
EXG A,B
exchanges the contents of the A and B registers. After the instruction, the A
register contains the value that was in the B register and the B register
contains the value that was in the A register.
The instructions TFR and EXG can be used to transfer or exchange the
contents of any pair of 6809 registers that are the same size. That is, you can
transfer or swap any pair of eight-bit registers, and any pair of 1 6-bit registers,
but you cannot transfer or exchange between an eight- and 1 6-bit register.
For example,
TFR A,CC
is valid because the both the A and CC (Condition Code register) are both
eight-bit registers, but
TFR A,X
is not allowed because the A register is eight-bit and the X register is 1 6-bit.
However, as the D register is 16-bit and is made up of the A and B registers
this forms a link between the 6809's eight- and 16-bit registers that can be
used to transfer and exchange values between all the registers.
Using the TFR instruction and constant offset indexed addressing, the
@DBAT subroutine becomes -
151
Language of the Dragon
CLRA
ADDD jl$05C0
TFR D,X
LDA @CHAR
STA 0,X
STA 1,X
STA 2,X
RTS
Constant offset indexed addressing is very useful if you want to use a few
memory locations next to each other, as in the @OBAT subroutine, but
consider the problem of zeroing a whole section of memory. You could use
something like -
LDX # @START
CLR 0,X
CLR 1,X
CLR 2,X
CLR 3,X
and so on until the appropriate amount of memory had been cleared. (The
addre5:5 of the first memory location to be cleared is labelled by @START.)
However, if the program had to clear say 100 locations this method would
result in rather a long program.
1 52
Chapter 9 The addressing registers - indexed addressing
LDA B,Y
loads the B register from the memory location whose address is obtained by
adding the contents of the B register to the contents of the Y register. Notice
that once again neither the contents of the B register nor the contents of the Y
register are affected by this instruction. The contents of the eight-bit registers
A and B are treated as two's complement values so, that using these
registers, you can address the current contents of a pointer register from -128
to + 127. The value in the D register is also treated as a two's complement
value when it is added to the pointer register so this gives a range of-32768 to
+ 32767 from the current contents of the pointer register. You may be a little
puzzled by an instruction like -
LDA A,Y
CLRA
LDX #@START
which can be further simplified if the memory can be cleared starting from
@START + 99 and working down to @START -
LDA #99
LDX #@START
1 53
Language of the Dragon
If you want to clear (or do anything else!) to more memory locations than
can be addressed by an eight-bit two's complement offset then you can
always use the D register to specify a 16-bit two's complement offset.
However, you should keep in mind the fact that while the D register is being
used to specify an offset, both the A and B registers are unavailable for
calculations unless the D registers value is saved and restored. One possible
solution is to use the EXG instruction to swap the D register's value with one
of the other pointer" register's.
LDA ,X+
means "load the A register from the memory location whose address is stored
in the X register and then add onetoX". In general, writing one plus sign after
the pointer register's name is taken to mean that 1 should be added to the
register AFTER the operation is complete, thus leaving the register 'pointing'
at the next memory location. Writing two plus signs after the register's name
will cause it to be incremented by 2 following the operation. Unfortunately
this is where it finishes. Writing three plus signs will simply give you an error
message. This adding one or two to the p0inter register after the operation is
known as 'auto increment mode'. If you want to use memory locations that
differ by 1 or 2 in ascending order then auto increment mode is by far the best
method. For example, the program to clear 100 memory locations is best
written as
CLRA
LDX Jl@START
@LOOP CLR ,X +
INCA
CMPA jl99
BLE @LOOP
1 54
Chapter 9 The addressing registers - indexed addressing
Notice that auto increment is only allowed with a constant offset of zero.
'Auto decrement' works in a very similar way to auto increment apart from
subtracting 1 or 2 BEFORE the instruction is completed. For example,
LDA ,-X
will first subtract 1 from the contents of the X register and then use the result
as the address of the memory location that A is loaded from. Notice that the
minus sign is written in front of the pointer to indicate that the
subtraction is done before the contents of the register are used as the address
of the memory location. In the same way, writing two minus signs in front of
the pointer register's name will subtract 2 from the register's value before it is
used as an address. Notice that in both cases the addition or subtraction
actually alters the value stored in the pointer register. Some valid example of
auto increment and decrement are -
LDA ,-X subtract 1 from the X register and then load the A
register from the memory location that it 'points'
at
STA ,--U subtract 2 from the U register and then store the
A register in the memory location that it 'points'
at
155
Language of the Dragon
LEAY 3,X
will load the Y register with the effective address calculated by 3,X. In other
words, after the instruction the Y register will contain the value in the X
register plus 3. You can use the LEA instruction to store an effective address,
calculated using a given pointer register, back into itself. For example,
LEAX 3,X
will store the effective address obtained by adding 3 to the current value of the
X register back into the X register. A common use of the LEA instruction is as
an increment or decrement of a pointer register. For example, another way to
write the program that clears 100 memory locations is,
CLRA
LDX @START
where the LEAX instruction adds one to the X register each time through the
loop. Notice that the LEA instruction can be used with any of the indexed
addressing modes. So for example,
156
Chapter 9 The addressing registers - indexed addressing
LEAX ,S+
LEAY A,X
LEAU D,U
are all valid LEA instructions. Notice that LEAX 1,X and LEAX -1 ,X are the
pointer register equivalents of INC and DEC.
1 57
Language of the Dragon
one of the pointer registers. The PC register is not a general purpose pointer
register but, to make relative addressing available to all 6809 operations, it can
be used in a constant offset indexed addressing mode called 'PC relative'. For
example,
LDA 5,PC
would access the memory location five memory locations further on from the
start of the next instruction (see relative addressing in Chapter Seven). In the
same way that the BASIC assembler automatically calculates two's
complement offsets for relative addressing, most assemblers will calculate
the correct offset for PC relative from the value of an address label. So -
LDA @DATA,PC
would calculate the offset required to load the A register from the memory
location labelled by @DATA,
Indirection
Like the last section, this one deals with a topic that can be left until you are
ready to tackle something new! 'Indirection' is, in principle, a simple idea that
can get a little complicated in practice! The idea of using an address to specify
a memory location is something that you should already be thoroughly
familiar with. However, in the 6809, an address is nothing more than a 16-bit
simple binary number and so it can be stored in two memory locations just like
any other 1 6-bit number. The idea behind indirection is that, instead of giving
the address of the memory location that holds the data, you supply the
address of a pair of consecutive memory locations that contain the address of
the memory location that contains the data! This idea is easier to understand
than it is to describe! If simple addressing is imagined as,
1 58
Chapter 9 The addrBssing registers . indexed addressing
memory
address � B
then indirect addressing can be depicted as:
two memory
locations memory
LDA $40 0 0
means load the A register with the contents o f memory location $40 0 0 but
LDA ($40 0 0 1
means that $40 0 0 and $4001 contain the address that the A register should be
loaded from. When indirection is used with indexed addressing the principle
is that the effective address is calculated first (ignoring the indirection) and
then this effective address is used as the address of the memory location
where the actual address is stored. For example,
1 59
Language of the Dragon
LDA 14,XI
will first add 4 to the contents of the X register to get the effective address and
then use this as the address of'the pair of memory locations that hold the
address of the data.
STA 1,X+ + I
and
STA 1,--XI
STA l,X + I
and
STA 1,-XI
are both invalid. The reason for this restriction is not difficult to see. If a
pointer register contains the address of a 1 6-bit address stored in two memory
locations, what is the purpose of adding or subtracting 1 from it to make it
point at half of the address pair?
The reason that indirect addressing is treated in this chapter is that ALL
indirect addressing including extended indirect addressing is implemented as
a variety of indexed addressing. You will find indirection a valuable tool when
you come to write large assembly language programs that are intended for
use by other programmers. For example, the Dragon's BASIC ROM contains
many uses of indirection. One that is worth mentioning is the indirect jump. If
you look at the table in Appendix I you will see that the JMP and JSR
instructions can be used with indexed addressing and so
JMP (address)
and
JSR (address)
7 60
Chapter 9 The addressing registers - indexed addressing
are both valid. You may find it difficult to think of a reason for using indirect
jumps but suppose that you were writing a large program consisting of a
collection of subroutines that kept changing. As the subroutines changed in
size their starting addresses would also change and any program that used
the subroutines would have to be updated to take into account their new
positions. However, if you followed the simple rule of placing all the
subroutine start addresses together in the form of a table · a 'jump table' • at
the start of your program and insisting that other programmers used the
subroutines by indirect jumps through the table then, as long as you kept the
table up-to-date, you could move the start addresses of the subroutines as
much as you liked without affecting anyone. This is in fact what is done in
most large programs but the use of indirect jump tables and such like really
comes under the heading of advanced assembly language programming and
be will returned to briefly in Chapter Eleven.
These are all of the possible indexed addressing modes. Notice that you
cannot combine modes to obtain new addressing modes. For example, LOA
3,X + + is illegal because auto increment can only work without an offset,
LOA -X + + + is illegal because you can only auto increment by 1 or 2 and
161
Language of the Dragon
LDA ,X-- is illegal because you can only auto decrement before the effective
address is used.
You can use indexed addressing without ever worrying about how it is
implemented in 6809 machine code but if you are at all interested in
understanding how an assembler works, or if you are interested in producing
efficient code, then it does help to know how an instruction like LDA 5,X is
assembled. In fact the constant offset indexed mode can be assembled into
machine code in four different ways depending on the range of the offset.
The section of the table dealing with constant offset indexed addressing
deserves a closer look. When writing assembly language the offset can be in
the range-32768 to + 32767 but always to include a 16-bit two's complement
offset would be very wasteful of time and memory. Most constant offset
indexed addresses are of the form O,X or 4,X, that is the offsets are usually
small. For this reason the machine code form of the constant offset indexed
address depends on the size of the offset. If the offset is zero or in the range
-16 to + 15 it can be included into the post byte giving a very fast, very short
instruction. If it is in the range -128 to + 127 the offset is too large to be
included in the post byte and so it has to be stored in the next memory location
giving the resulting indexed instruction the following form
162
Chapter 9 The addressing registers inde1<ed addressing
(where offset 1 holds the most significant byte and offset 2 holds the least
significant byte.) Notice that a constant offset indexed addressing mode
instruction can occupy as little as two memory locations or as many as five if
the machine code itself occupies two of them. Also notice that there is more
than one way to write an instruction involving a small offset. For example,
LDA O,X can be assembled as a zero offset instruction into two bytes, as a
five-bit offset instruction in two bytes, as an eight-bit offset in three bytes or
even as a 16-bit offset in four bytes! In most cases a good assembler will
choose the most economical form of any indexed addressing mode and leave
the programmer to worry about more interesting things.
LDA > $3 1
163
Language of the Dragon
LOOPinstruction and so the only way to modify the OP register is by the TFR
or EXG instructions. For examDle, following
LDA jl$04
TFR A,DP
the OP register contains $04 and any direct addresses refer to the range $0400
to $04FF. ln other words an instruction like STA > $32 will store the contents
of the A register in memory location $0432, the most significant eight bits
coming from the OP register and the least significant eight bits coming from
the direct address.
164
Chapter 9 The addressing registers - indexed addressing
where the code for the source register is stored in the most significant four
bits and the code for the destination register is stored in the least significant
four bits. So, for example, TFR U,S would assemble to -
$1 F $34
where $1 F is the machine code for TFR and $34 is the code for the U register
($31 and the S register ($4) is indicated in the table given above.
1 REM BASIC ASSEMBLER V9.1
81 DATA LDX,&H8E,&H9E,&HAE,&HBE,-1
82 DATA LDY,&H108E,&H109E,&H10AE,&H10BE,-1
83 DATA LDS,&Hl0CE,&Hl0DE,&Hl0EE,&Hl 0 FE,-1
84 DATA LDU,&HCE,&HDE,&HEE,&HFE,-1
85 DATA STS,-1,&H10DF,&H10EF,&H10FF,-1
86 DATA STU,-1,&HDF,&HEF,&H FF,-1
87 DATA STX,-1,&H9F,&HAF,&HBF,-1
88 DATA STY,-1,&H109F,&H10AF,&H10BF,-1
89 DATA CMPS,&H118C,&H119C,&H11AC,&H 11BC,-1
90 DATA CMPU,&H1183,&H1193,&H11A3,&H11B3 ,-1
91 DATA CMPX,&H8C,&H9C,&HAC,&HBC,-1
92 DATA CMPY,&H108C,&H109C,&H10AC,&H10BC,-1
93 DATA LEAS,-1,-1,&H32,-1,-1
94 DATA LEAU,-1,-1,&H33 ,-1,-1
95 DATA LEAX,-1,-1,&H30,-1,-1
96 DATA LEAY,-1,-1,&H31,-1,-1
97 DATA ABX,-1,-1,-1,-1,&H3A
98 DATA EXG,&Hl E,-1,-1,-1,-1
99 DATA TFR,&Hl F,-1,-1,-1,-1
199 DATA ZZZ,-1,-1,-1,-1,-1
165
Language of the Dragon
5800 TYPE = 3
5810 L$ = MID$(A$(1),K-1 , 1 )
5820 OF=0
5830 IF L $ = "A" T H E N O F = &H86
5840 IF L$ = "B" THEN O F = &H85
5850 IF L$ = "D" THEN OF= &H88
5860 L$ = MID$(A$(1),K + 1, 1)
5870 IF L$= "-" THEN L$= MID$(A${1),K + 2,1 ):OF = &H82
5880 IF L$ = "-" THEN L$ = MID$IA$(1), K + 3,1):OF = &H83
5890 RF=0
5900 IF L$ = "Y" THEN R F = l
5901 I F L$ = "U" THEN R F = 2
5902 IF L$ = "S" THEN R F = 3
166
Chapter 9 The addressing registers · indexed addressing
Subroutine 5800 processes indexed addressing by making up the code for the
post byte in accordance with the Indexed Addressing Modes Table in
Appendix I Subroutine 5100 handles the coding of the byte following the EXG
or TFR instruction indicating which pair of registers are involved. Notice that
subroutine 6000 has to be modified to print and POKE the correct number of
memory locations for a 16-bit constant offset.
The processing of the address fields for both indexed addressing and the
EXG and TFR instructions is very crude and doesn't allow for blanks included
in the instruction. So, for example, you must write EXG A,B rather than EXG
A, B and LDA 0,X rather than LDA 0 ,X.
1 67
Language of the Dragon
@NUM1 and the second stored with its most significant byte at @NUM2 and
store the answer starting at @ANS use -
@ADD LOB @N
LOX #@NUMl
LEAX B,X
LOY #@NUM2
LEAY B,Y
LOU #@ANS
LEAU B,U
ANDCC jl$FE
To subtract the two numbers simply change the ADCA instruction to SBCA.
Notice the way that the three pointer registers X, Y and U are used with auto
decrement to 'step through' the memory locations of each number. Also
notice the way that the C bit is cleared before the first add so that the ADC
instruction can be used to add the first memory locations without error. The
LEA instructions at the start of the program adjust the pointer registers to
point to one memory location before the least significant byte of the numbers
because the auto decrement happens before the effective address is used.
Although you might not think so from the limited beeping that BASIC
restricts you to, one of the most flexible features of the Dragon is its sound.
This section ls concerned with generating sounds on the Dragon and
provides plenty of opportunity to use indexed addressing.
168
Chapter 9 The addressing registers - indexed addressing
There are three ways in which a steady tone can vary, in volume, in pitch
and in quality. All steady -tones are the result of periodic waveforms. The
volume is related to the amplitude of the waves, the pitch to the rate of
repetition and the quality to the shape of the wave. For example, the purest of
all tones is a perfect sine wave (see fig 9.1 l. A particularly rough sounding
tone is produced by the 'sawtooth' wave form (see fig 9.2). To produce the
sawtooth wave form all that is necessary is to store a series of numbers that
increase to some maximum and then reduce to zero and so on in location
$FF20. Obviously to create tones with a given quality it would be useful to
have a program that allowed the user to specify a series of numbers and then
hear the tone that they produce. An assembly language program to do this is
quite easy to write, the only difficult part being to find a good way of letting
the user specify the series of numbers. This is a task that is better suited to
BASIC and so in this section the use of assembler together with BASIC will be
examined.
The following assembly language program will take the series of values
stored in memory starting at $7F00 and then repeatedly store them in memory
location $FF20 so that you can hear the quality of the sound they produce.
This part of the program is fairly easy but to provide flexibility, the program
has to allow the user to decide how many values are specified and how long
the delay should be between storing each value. The number of values is
stored at $7EFF and the delay at $7EFE. Also, if the program is going to be
used as part of a BASIC program for designing sounds, there should be some
way to determine how long the sound should last. The sound duration is thus
specified in memory location $7EFD in fiftieths of a second so that it can be
compared with the Dragon's TIMER clock.
169
Language of the Dragon
MAX
O Volts
MAX
0 Volts
1 70
Chapter 9 The addressing registers - indexed addressing
Subroutine @INIT sets up the Dragon's sound channel so that you can hear
the results of the program and @DELAY is a typical delay subroutine as
described in Chapter Eight. The rest of the program is concerned with moving
the values in memory to $FF20 over and over again for the correct duration.
171
Language of rhe Dragon
Notice the way that the A register is used to determine both which memory
location will be transferred to $FF20 and when all of the locations have been
transferred.
If you just EXEC this program you the results that you get will depend on
whatever happens to be stored in the memory locations used for its data. To
make the program useful it has to be used with a BASIC program that sets the
data area to something appropriate. A machine code program can be saved
on tape using
THis command will save on tape the contents of memory from 'start' to 'end'
(where 'transfer' = end - start). To save the sound program use -
CSAVE "SOUND",&H7000,&H7030,&H31
After saving the sound program delete the BASIC assembler using NEW and
type in the following program -
10 CLEAR 1000,&6FFF
20 INPUT "HOW MANY VALUES";V
30 IF V>255 THEN GOTO 20
40 POKE &H7EFF,V
50 FOR I -1 TO V
60 PRINT "VALUE ";I;" - ";
70 INPUT A
80 IF A> 255 THEN GOTO 60
90 POKE &H7F00 + I-1,A
100 NEXT I
110 INPUT "PITCH";P
1 20 IF P> 255 THEN GOTO 110
130 POKE &H7EFE,P
140 INPUT "DURATION";D
150 IF D> 255 THEN GOTO 140
160 POKE &H7EFD,D
170 EXEC &H7000
180 GOTO 110
172
Chapter 9 The addressing registers - indexed addressing
CLOAOM "SOUNO",O
When the BASIC program is RUN it will use the machine code to let you hear
the quality of the note produced by the list of values that you type in.
Altering the quality of the sound using the waveform works well for steady
tones but most sounds contain a range of pitches. For example, a typical
'laser zap' in a space game will start off at a high pitch and descend to a low
pitch. This is fairly easy to do if the wave form is kept simple and the simplest
waveform to program is a square Wave.
Steady tones and tones that change in pitch are not all that the Dragon can
produce. Many special effects are based upon 'white noise'. White noise, a
sound rather like that made by a radio between stations corresponds to a
jumbled non-repeating wave form (see fig 9.3). To produce this sort of wave
form requires a source of numbers that are as good as random. The trouble is
that it takes rather too long to generate random numbers using the BASIC
AND function. An alternative source of varied numbers that provides a fair
1 73
Language of the Dragon
MAX
0 Volts
Fig 9.3 White r.oise
1 74
Chapter 9 The addressing registers - indexed addressing
You can send different sections of the ROM to the sound generator simply
by changing @START and @END.
To give you some idea of how to use white noise the following program
generates a 'gunshot' effect by progressively fading down the white noise-
Notice the way that the volume is faded down by AN Ding the number with
the contents of @VOL.
Summary
1 l There are five addressing registers-
2) Both the index registers and the stack pointers can be used for
indexed addressing.
1 75
Language of the Dragon
8) The TFR and EXG instructions can be used to move data between
all of the 6809's registers.
Micro projects
1 1 In Chapter Eight a delay subroutine was given that used the D register.
Re-write it using one of the pointer registers as a counter.
2) Write a short BASIC program that will use the SOUND subroutine
given earlier to produce white noise by POKEing random numbers in the
sound table (starting at @TABLEl. Use RND to generate the numbers (in the
range O to 63) and try experimenting with the values of pitch and duration.
176
Chapter Ten
A 'stack' is one of the most useful ways of storing temporary data. The 6809
uses a stack to hold the return address following a JSR or BSR instruction. As
well as this implicit use of a stack by JSR and BSR instructions, assembly
language programs can make more direct use of stacks to store data. The
subject of stacks and how they are used brings us to a consideration of
'interrupts'. Interrupts are the main way that a computer can be made to
respond to the outside world. In the case of the Dragon, the most interesting
use of interrupts is in providing the BASIC TIMER facility. In this chapter both
general stack operations and interrupts are described. The chapter closes
with an example of how an interrupt routine can improve the Dragon's
keyboard.
A stack
177
Language of the Dragon
The PSH and PUL operations on the stack produce a 'Last In First Out' or
'LIFO' effect. For example, if you push three numbers on to the stack in the
order 1, 2, 3 the stack will look like this (SP is the stack pointer):
|
I 1
-----
I 2 |
-----
SP -------> |I 3 |
-----
| |
Carrying out a PUL on the stack will retrieve 3 and leave the stack pointer
pointing as 2. Thus a second PUL will retrieve thevalue2 and a third, the value
1 . The numbers went in 1 , 2, 3 but came out 3, 2, 1 . That is, the last number
onto the stack came out first.
178
Chapter 10 The Stack Pointers and Interrupts
will push the contents of the X, Y and A registers onto the S stack. The other
three instructions, PULS, PSHU and PULU, can also pull or push a list of
registers. For example,
PULS X,Y,A
will restore the values that were pushed onto the S stack by the PSHS X,Y,A
instruction to the X, Y and A registers - as long as nothing else has been
pushed onto the stack in the mean time. The only restriction on the regiSter
list is that you cannot pull or push the S register onto the S stack nor the U
register onto the U stack.
You might be wondering about the order that the registers are pushed or
pulled. The order that you write the registers in the register list doesn't affect
the order that the registers are pushed or pulled. For example,
PSHS X,Y
is the same as
PSHS Y,X
In fact the order that the registers are pushed on to the stack is strictly
predetermined by the following priority -
1 PC
2 U or s
3 y
4 X
5 DP
6 B
7 A
8 cc
From a list of registers that are to be pushed onto the stack the registers
corresponding to the lowest numbers are pushed first. For example, in
PSHS CC,A,X
179
Language of the Dragon
the X register is pushed first, then the A register then the CC register. In other
words PSHS CC,A,X is the same as
PSHS X
PSHS A
PSHS CC
The order in which registers are pulled from the stack is the reverse of the
order in which they are pulled. That is, the registers in a register list will be
pulled so that the highest numbered registers are pulled first. So
PULS X,B,CC
is the same as
PULS CC
PULS B
PULS X
Apart from the PSH and PUL instructions, there are no other stack
operations. However, as the stack pointers are both general pointer registers,
values on the stack can be manipulated using indexed addressing. For
example,
PSHSA
ADDA,S+
doubles the value in the A register by first pushing its value on the stack and
then adding it back into the A register. Notice the way that auto increment on
the S register returns it to its original value before the PSHS - thus 'cleaning
up' the stack. It is important that, if you use a stack to store temporary data,
you remove it and leave the stack as you found it. Otherwise you could find
some odd things happening. In particular, if you push more onto the stack
than you pull off the stack will eventually grow to occupy all of the memory!
Notice that it is in general necessary to allocate sufficient memory to a stack
so that it doesn't overflow into areas of memory that are being used for other
purposes. ln the Dragon the S stack is usually initialised by the system to be
just below the temporary string storage area used by BASIC.
180
Chapter 10 The Stack Pointers and Interrupts
Interrupts
The idea of an interrupt is so familiar to humans that it is hardly worth a
second thought. If you are reading a book and the telephone rings you would
have no difficulty in marking your place in the book, answering the phone arid
then, after the call is complete, returning to the marked place in the book as if
nothing had happened. Contained in this description are the essential
elements of all interrupt handling. First there is a signal from the outside world
- the interrupt. As a result of this interrupt the current preoccupation is
suspended but enough information is stored to enable the task to be restarted
after the interrupt has been dealt with. The interrupt is dealt with and then the
original occupation is restored.
The 6809 can respond to three different types of interrupt - the NMI
(Non-Maskable Interrupt), IRQ (Interrupt ReQuest) and FIRQ (Fast Interrupt
ReOuestl. Each of these types of interrupt corresponds to a physical
connection to the 6809 chip inside the Dragon. A signal on one of these
connections indicates a request to interrupt the 6809 from whatever it is
currently doing. Exactly what happens following an interrupt depends on
which source caused the interrupt.
IRQ Following a signal on the IRQ line the 6809 completes the instruction
that it is carrying out, then it stacks all of the registers and jumps to the
location whose address is stored in $FFF8 and $FFF9. In other words, after
181
Language of the Dragon
stacking all the registers, the6809 executes a JMP {$FFF8 ) . In the Dragon the
address $FFF8 is shifted t,y hardware down into the BASIC ROM at $BFF8
which contains the address $01 0C. This means that an IRQ interrupt transfers
control to $010C. Details of what the Dragon uses the IRQ interrupt for will be
given later.
NMI Following a signal on the NMI line the 6809 completes the instruction
that it is carrying out then it stacks all of the registers and jumps to the location
whose address is stored in $FFFC and $FFFD. In the Dragon the address
$FFFC is shifted by hardware down into the BASIC ROM at $BFFC which
contains the address $0109.
,_
FIRQ Following a signal on the FIRQ line the 6809 completes the
instruction that it is carrying out and then stacks the PC register and the CC
register and then jumps to the location whose address is stored in $FFF6 and
$FFF7. Notice that in this case not all of the registers are stacked following a
FIRO interrupt. It is this that makes it a fast interrupt. In the Dragon the
address $FFF6 is shifted by hardware down into the BASIC ROM at $BFF6
which contains $010C. The FIRO is only used in the Dragon to detect the
presence of a ROM program cartridge.
The three types of interrupt have one thing in common they all save some
of or all of the registers on the system stack and then do an indirect jump
through a fixed location. The destination of the jump is a program usually
referred to as an 'interrupt handler'. What exactly the interrupt handler does
depends very much on what caused the interrupt. For example, in the case of
the Dragon the \RO handler adds one to the current value of memory
locations used for the timer. Once the interrupt handler has finished control
182
Chapter 10 The Stack Pointers and Interrupts
has to be returned to the program that was interrupted. This is done by using
the RTI (ReTurn from Interrupt) instruction which is to an interrupt what the
RT$ instruction is to a subroutine. The RTI not only returns control to the
program that was interrupted, it also restores to their original registers any
values that were pushed onto the stack by the interrupt. If all of the registers
were pushed onto the stack then following an RTI the 6809 is back to its
original condition before the interrupt even if the interrupt handler used some
of the registers. However, if the interrupt only saved some of the registers,
then the interrupt handler has to be careful not to alter any of the registers that
are not going to be restored by the RTI instruction.
b7 b6 b5 b4 b3 b2 bl bO
E F H I N Z V C
The H, N, Zand C bits have already been described in Chapter Seven. The Eor
Entire bit is used by the RTI instruction to discover how many registers were
pushed onto the stack by the interrupt and so how many registers should be
pulled off the stack before returning control to the program that was
interrupted. If the E bit is 1 then all (i.e. the entire set) of the registers were
pushed and so the RTI results in
PULS CC,A,B,DP,X,Y,U,PC
If the E bit is O then only the CC and PC register are pulled from the stack -
PULS CC,PC
There is a subtle point here. As the RTI instruction pulls the CC register off the
stack, which value of the E bit does it take notice of? The answer is that it first
restores the CC register by pulling it off the stack and then it examines the E bit
to discover how much more has to be pulled off the stack. This means that an
interrupt handler can change the CC bits as much as it likes and the RTI
183
Language of the Dragon
instruction will get it right. You can in fact manipulate the E bit stored on the
system stack to change the action of an RTI instruction for special purposes
but take great care that you pull the right things of the stack. For example,
suppose an IRQ handler didn't use any of the registers that the main program
was using. then you could save the unnecessary 'unstacking' of the entire
register set by -
PULS A
ANDA jl$7F
LDS7,S
PSHSA
RTI
The first instruction pulls the value that would be returned to the CC register
following an RTI and places it in A. The E bit is then set to O (by AN Ding with
$7F), the stack pointer is adjusted to get rid of the unnecessary register values
that were stored and then the new value for the CC is PSHed into the correct
position on the stack. The following RTI will now only restore the CC and PC
registers because the E bit is O. This sort of trick iS only worth using when your
are desperate to make a program run faster and it can lead to programs that
are very difficult to debug.
The I and F bits are both concerned with stopping interrupts having any
effect. The 6809 will only take any notice of IRQ signals if the I bit isO. Thus the
I bit can be used to mask the effects of interrupts, Setting and clearing it can
be used to control when an interrupt is allowed. The instruction
ANDCC jl$EF
ORCC jl $1 0
sets i t t o 1. The F bit will similarly disable FIRQ interrupts. I f the F bit is O then
the 6809 will take notice of signals on the FIRQ line but it will ignore them is F is
1. The instruction -
ANDCC jl$BF
184
Chapter 10 The Stack Pointers and Interrupts
ORCC jj,$40
sets it to 1 .
This means that following an IRQ interrupt the interrupt handler will not be
interrupted by IRQ again but it will be interrupted by an FIRQor a NMI. In this
sense both FIRQ and NMI have a higher priority than IRQ.
21 The F and bits are bah set to 1 to mask any further FIRQ or IRQ
interrupts
In general there are two ways of stopping an IRQ or FIRQ interrupt. You
can stop it at source by altering the device that produces it, or you can set the
CC register so as to mask the interrupt. The device that causes the interrupt
usually has to be reset in some way or another before it can cause another
interrupt. Resetting, and any other operations that the external · device
requires, are all the responsibility of the interrupt handler. Indeed it is possible
that more than one external device can cause an interrupt and in this case the
1 85
Language of the Dragon
first job that the interrupt handler has to tackle is to find out what caused the
interrupt. As you can imagine, in general use interrupts can become very
complicated.
The normal use of an interrupt sigrial is to stop the 6809 from what it is
doing and transfer its processing powers to a different and perhaps more
urgent task. However, there are occasions when the 6809 has nothing bener
to do than wait for an interrupt to occur. The two instructions CWAI (Clear
and WAit for Interrupt) and SYNC (SYNChronise) are both concerned with
making the 6809 suspend its operation until something causes an interrupt.
The CWAI #$XX instruction ANDs the CC register with the immediate byte,
stacks all of the registers on the system stack and then waits for an enabled
interrupt. The immediate byte can be used to �elect which interrupt signal will
be enabled. Notice that the CWAI instruction will cause even the FIRO
interrupt handler to be �ntered with all the registers stored on the stack. The
CWAI instruction can save time in handling interrupts because when the
interrupt occurs the registers are already stacked.
It may seem strange but the idea of an interrupt is so useful that the 6809
has three instructions that will force the 6809 to behave as if it had received an
external interrupt signal! SWI (SoftWare Interrupt), stacks all the registers,
sets the I and F bits to mask external interrupts and then cause an indirect
186
Chapter 10 The Stack Pointers and Interrupts
jump to $FFFA. In the Dragon this address is moved using hardware down to
$BFFA. The SWI2 and SWl3 also stack all ofthe registers but they don't mask
external interrupts. SWl2 causes an indirect jump through $FFF4 which the
Dragon's hardware has moved down to $BFF4 and the SWl3 instruction
causes an indirect jump through $FFF2 which the Dragon's hardware has
moved down to $BFF2.
The instructions RTI, CWAIT, SYNC, SWI, SWl2 and SWl3 can all be
added to the BASIC assembler simply by including the appropriate DATA
statements. However, to accomodate PSH and PUL the handling of the
address field has to be extended once again. Both PSH and PUL use the byte
following their machine code to store the list of registers to be pushed or
pulled according to the following table:
PC S/U y X DP B A cc
128 64 32 16 8 4 2 1
The value stored in the following byte is the sum of the codes corresponding
to each register to be pushed or pulled. So, for example, the machine code
for-
PSHS PC,X,A
is
$34 $92
where $34 is the machine code for PSHS and $92 = 128 + 1 6 + 2 is derived
from the above table.
187
Language of the Dragon
The new subroutine 5300 processes the address field following a PSH or a
PUL and makes up the value to be stored in the memory byte following the
machine code for the instruction according to the previous table.
188
Chapter 10 The Stock Pointers and Interrupts
We already know that the Dragon's hardware moves all of the memory
locations used by the interrupts down into the BASIC ROM but what hasn't
yet been mentioned is that you can change the destination of an interrupt.
Each of the 6809's interrupts causes an indirect jump through memory
locations in ROM down to a series of memory locations in RAM. These RAM
memory locations, for those interrupts that are used, contain JMP
instructions that finally transfer control to the interrupt handlers. The
important point is that as the JMP instructions are stored in RAM they can be
changed and so, interrupts can be intercepted on their way to their interrupt
handlers. This situation is best summarised by the following table:
Interrupt indirects indirects contents
through to
SWl3 $8FF2 $10 0 0
SWl2 $8FF4 $103 0
FIRQ $8FF6 $10 F JMP $8469
IRQ $ 8FF8 $1 0 C JMP $9D3D
SWI $ 8FFA $1 0 6 JMP $D521
NMI $8FFC $1 09 0
Reset $8FFE $8384 -----
The meaning of this table should be clear but, to take an example, an IRQ
interrupt indirects though $BFF8 which contains the address $01 0 C. Thus,
following an IRQ, control passes to $010 C which contains the instructions
JMP $9 03 0 which finally transfers control to the interrupt handler. Notice
that the table contains an entry for 'Reset' which indicates where the 6809
transfers control to when the reset button is pressed. Some of the 6809's
interrupts are not used on the Dragon and this is indicated by the memory
locations in the table containing zeros, These unused interrupts could be put
to use by applications programs but there is always the possibility that future
Dragon systems programs will use one of them with resulting conflict.
The only two interrupts that the standard Dragon uses are FIRO and IRQ.
The FIRO interrupt is used by a cartridge ROM to gain control from BASIC
and start its own program running. The IRQ interrupt is used to produce the
1 150th of a second clock. The way that this works is that the TV frame sync
pulse is connected to one of the PIAs which causes an IRQ interrupt every
1 150 th of a second. (For more information see "The Anatomy of the
Dragon".)
189
Language of the Dragon
The first part of the program @AUTO first disables the IRQ interrupts and
then changes the JMP $9030 to JMP @REP. The @REP subroutine simply
sets the memory locations to $FF and then jumps to the original interrupt
handler. The address of the original interrupt handler is stored in @TIM and
the JMP O,X instruction transfers control to the the address stored in X. To
use this program simple EXEC it once after assembling it and, every 1 /50th of
a second, it sets the memory locations to $FF and produces an auto repeat.
You may find that 1 150th of a second is a little fast for an auto repeat and so
the final version of the program produces a repeat every 1 /2 of a second by
counting the number of interrupts between each setting of the memory
locations. The following section needs to be added to the @AUTO part of the
previous program:
1 90
Chapter 10 The Stack Pointers and Interrupts
Even with this improvement the auto-repeat program needs some work to be
useful. Ideally a key should not auto repeat until it has been held down for
some minimum time and then it should repeat at quite a fast rate.
Summary
1) The 6809 has two stacks - the system stack using the S register
as the stack pointer and the User stack using the U register as the
stack pointer.
3) Of the three 6809 interrupts only the IRQ interrupt that is used to
produce the system clock is likely to be useful to the assembly
language programmer working with an unmodified Dragon.
191
Language of the Dragon
Micro project
1 ) Use the SYNC instruction to ensure that the squash program given in
Chapter Eight only changes the display once every 1 150th of a second. Hint
you only need to modify the @DELAY subroutine.
192
Chapter Eleven
Once you have mastered the details Of 6809 assembler the only way to extend
your skill is to write programs. As with nearly all aspects of computing,
practice is essential. Assembler is a powerful language and if a program using
a good method doesn't work fast enough in assembler then there is nothing
you can do but get a better computer! Although assembler is powerful you
still have to know how to solve the problem that you are interested in and in
some ways this can be more difficult in assembler than in a high level
language. If you have no idea of how to go about solving a problem using
BASIC then you have little chance of getting any further with assembler.
Despite the fact that there is no way of becoming a proficient assembly
language programmer without practice, there are a few guidelines and
suggestions that are worth knowing about.
Subroutines
It is well known that the best way to write a large program is to break it
down into a collection of smaller programs. It is almost impossible to think of
a large program without dividing it down into sections that perform specific
tasks and it makes sense to write such a program in a way that reflects these
divisions. ln BASIC and in assembler the subroutine is the standard way of
writing the small 'modules' that fit together to produce a finished program.
The use of subroutines in assembler is all the more important because of the
very limited operations that the language offers you. In principle whenever
you write an assembly language program your objective should be to build up
a collection of subroutines that carry out more complex operations. This
collection of subroutines can not only be use to implement the current
program they form a programmer's 'inheritance' to be used in future
193
Language of the Dragon
programs. For example, if you are writing a program that needs to carry out
any amount of arithmetic then you need to write some subroutines to carry
out arithmetic. Perhaps less obviously, if you are writing a games program or
a graphics program you should first write subroutines to plot a single point in a
given colour and then build up subroutines that plot the shapes that you are
using. In this example, notice that the shape drawing subroutine would use
the dot plotting subroutine to produce the shape. This is typical of the way
that assembly language subroutines that do complicated things usually rely
on simpler assembly language programs to do the 'dirty work' for them.
Another advantage of using subroutines as the building blocks of larger
programs is that, in principle, any errors in the program should be isolated
within a subroutine and so any changes that are necessary to put the error
right should be isolated to a small area of the program. However, this neat
theory of isolated errors will only work if you follow a strict method of writing
subroutines so that they don't interact in ways that you never intended.
194
Chapter 11 Assembly Language Style and Practice
where the memory location @TIME is used to specify the desired delay before
calling the subroutine. Notice that the X register is freely used by this
subroutine and there is no attempt to restore its original value at the end of the
subroutine. The second method of writing the subroutine would give:
The only difference is that the CC and X register are pushed onto the system
stack and restored at the end of the subroutine. As the X and the CC register
are the only two registers used by the subroutine we can guarantee that the
subroutine produces its effect, i.e. a delay, without changing the values
stored in any register.
1 95
Language of the Dragon
The @D ELAY subroutine now requires the delay value to be pushed onto the
stack before it is called
Notice that after pushing the value $1000 on the stack the BSR instruction
automatically pushes the return address in front of the value. This ls the
reason that the @DELAY subroutine has to take its data from .2, S rather than
0,S. Also notice that after using the subroutine the stack has to be cleaned up
either by pulling a two byte value off the stack or, as shown above, simply by
subtracting 2 from the S register. The topic of using the stack for temporary
storage in conjunction with subroutines is too large a subject to be pursued
anyfurther here. (For further information see "The6809 Companion N by Mike
James, published by Babani, 1982.1
196
Chapter 1 1 Assembly Language Style and Practice
As well as being useful for checking that a programming idea works before
committing yourself to assembly language, there is no avoiding the fact that
BASIC is better than assembler for some tasks. In Chapter Nine the one of the
sound producing programs was written to be used in combination with a
BASIC program that provided it with data by prompting the user in a way that
would have been very tedious to write in assembler. Where speed isn't
required then BASIC is generally to be preferred. For this reason the ideal way
to write a program is to use a mixture BASIC and assembler.
DEFUSRn =XXXX
DEFUSR0 = &H7000
A = USR00l41
(Notice that the DEFUSRO identifies the function using only a single digit but
the function itself uses two digits, i.e. USROO rather than USRO.) This
function would find the square root of four and place the result in the BASIC
variable A. You can use a machine code function in exactly the same way that
you use an ordinary function. For example,
A = 2*USR00(X*4 +21 +4
When BASIC transfers control to a machine code USR function it sets the
X register to point to an area of memory known as the 'floating point
accumulator' or 'FAC'. This holds the result of evaluating the expression
contained within the brackets when the function was called. The only trouble
is that this value is stored in a representation that would take too long to
explain in any detail here called 'floating point binary'. The essence of this
representation is that a number is stored in five bytes, the first of which (the
one that the X register points at) being the binary exponent+ 128. The next
four bytes i.e. X + 1, X + 2, X + 3 and X + 4 contain the mantissa in normalised
form. In the FAC a sixth byte is also stored at X + 5 which isa copy of the most
significant byte of the mantissa but with b7 set to 1 if the number is negative
and b7 set to O if the number is positive. For a machine code function to do
anything useful with this floating point number would be rather complicated
so it is usual to convert itto a 16-bit integer using the machine code subroutine
stored at $8B2D which returns the value of the FAC in the D register. To
convert a value in the D register back into floating point form use the
subroutine at $8C37 which will leave the value in the FAC. As the result that is
returned by the USR function is the value that is stored in the FAC before the
final RTS returns control to BASIC, subroutine $8C37 can be used to store
the correct floating point value when the USR function has finished its
calculations.
198
Chapter 11 Assembly Language Style and Practice
1 DEFUSR0 = &H7000
2 INPUTA
3 PRINT USR00(AI
4 GOTO2
You could try using the function in even more complicated expressions just to
check that everything works as predicted.
If you want to access any variables, strings or arrays using a machine code
USA function then it is worth knowing that the VARPTR function will leave
the address of any variable in the FAC. For example, USR01 (VARPTR(" A$))
leaves the address of the first byte of the string description in the FAC (see
"The Anatomy of the Dragon").
Now that you have worked your way though this brief introductory look at
Dragon assembler you must tackle some assembly language projects to
develop your skills yet further. Before you can do this, however, it is worth
investing in a good quality assembler. Two commercial assemblers are
described in Appendix II and now that you have experience of how an
assembler works via the BASIC assembler you should be in a position to
evaluate such software for yourself! However, if buying a ready made
assembler seems like the easy way out then you might like instead to tackle
the large project of writing your own assembler lin assembler!) taking the
BASIC assembler as your model. In case you choose this course, and for
general interest, it is worth pointing out some of the features that have been
199
Language of the Dragon
left out of the BASIC assembler that are commonly found in commercial
assemblers.
The idea of a label to represent an address is usually taken one stage further
to include 'address' or 'label expressions'. For example, if @TABLE is a label
that marks the start of a sequence of memory locations that are being used to
store data, then it is often the case that a particular instruction always needs
to make reference to say the second location in the table. Using a label
expression this would be written as @TABLE+ 1, in other words, the
memory location whose address is given by adding one to the address value
that corresponds to @TABLE. Notice that this expression, i.e. @TABLE+ 1 ,
i s evaluated b y the assembler and used a s the address i n a n instruction. In
contrast the seemingly similar
LDX #@TABLE
LEAX 1 ,X
causes the 6809 to work out the same address only when the machine code
program is finally run. It is this potential for confusion that makes it wise to
leave address expressions alone until you are completely happy with the
simpler aspects of addressing.
Commercial assemblers also offer a wider range of constants than just the
hex and decimal numbers that the BASIC assembler will handle. Most will
allow you to specify numbers in binary and will automatically convert
characters to their corresponding ASCl1 codes automatically. For example, in
the DASM assembler -
LDA #!A
will load the A register with the ASCII code for " A" into the A register. Also all
commercial assemblers will automatically convert negative numbers used in
address expressions into the correct two's complement form. For example,
LDA #-1
will load the A register with the two's complement representation of -1 i.e.
$FF. This facility is not available not in the BASIC assembler as it stands.
200
Chapter 11 Assembly Language Style and Practice
All of these features and more could be added to the BASIC assembler but
it would still not be up to the job of assembling large programs because of the
time it takes to assemble each line.
As well as a good efficient assembler you also need some way of debugging
a machine code program. The most usual way is to use a machine code
monitor program such as DEMON from Compusense or DREAMBUG which
is contained on the ALLDREAM cartridge from Dragon Data. A monitor is a
program that allows you to examine areas of memory, discover the contents
of registers and trace the execution of a program instruction by instruction.
Whenever a machine code program fails to work, it is either a matter of some
very obvious mistake needing to be put right or the machine goes quiet and
you are left to ponder what might have gone wrong! In this second situation a
machine code monitor is the only way that you can check the misbehaving
program instruction by instruction to test that it does what you expect it to.
201
Appendix I
I nstruction Codes
ABX 3A -----
ADCA 89 99 A9 89 a a a a a
ADCB C9 D9 E9 F9 a a a a a
ADDA 88 98 AB BB a a a a a
ADDB CB DB EB FB a a a a a
ADDO C3 D3 E3 F3 _ a a a a
ANDA 84 94 A4 B4 _ a a 0 __
ANDB C4 D4 E4 F4 __ a a 0 __
ANDCC lC *
ASLA 48 u a a a a
ASLB 58 u a a a a
ASL 08 68 78 u a a a a
ASRA 47 u a a
ASRB 57 a a
ASR 07 67 77 a a _ a
202
Appendix/
SITA 85 95 A5 85 _ a a 0 __
81TB C5 D5 E5 F5 _ a a 0 __
CLRA 4F __ 0 1 0 0
CLRB 5F _o 1 0 0
CLR OF 6F 7F _o 1 0 0
CMPA 81 91 A1 81 u a a a a
CMPB C1 D1 E1 F1 u a a a a
CMPD 1 083 1093 1 0A3 1 083 _ a a a a
CMPS 1 1 8C 119C 11AC 1 1 BC _ a a a a
CMPU 1 1 83 1193 11A3 1 1 83 _ a a a a
CMPX BC 9C AC BC _ a a a a
CMPY 108C 109C 1 0AC 10BC __ a a a a
COMA 43 _ a a 0 1
COMB 53 _ a a 0 1
COM 03 63 73 _ a a 0 1
CWAI 3C *
DAA 19 _ a a 0 a
DECA 4A _ a a a __
DECB 5A _ a a a __
DEC 0A 6A 7A _ a a a __
EORA 88 98 A8 88 _ a a 0 __
EORB CB D8 E8 F8 _ a a 0
EXG 1E -----
INCA 4C _ a a a __
INCB 5C _ a a a __
INC oc 6C 7C _ a a a __
JMP OE 6E 7E - - - - -
JSR 9D AD 8D -----
LDA 86 96 A6 86 _ a a 0 -
203
Language of the Dragon
LDB C6 D6 E6 F6 _ a a 0 _
LDD cc DC EC FC _ a a 0 _
LDS l 0CE l 0DE l 0EE l 0FE _ a a 0 _
LDU CE DE EE FE _ a a 0 _
LDX 8E 9E AE BE _ a a 0 _
LDY 108E 1 09E l0AE l0BE _ a a 0 _
LEAS 32 - - - - -
LEAU 33 - - - - -
LEAX 30 _ _ a _ _
LEAY 31 _ _ a _ _
LSLA 48 _ a a a a
LSLB 58 _ a a a a
LSL 08 68 78 _ a a a a
LSRA 44 _o a _ a
LSRB 54 _o a _ a
LSR 04 64 74 _o a _ a
MUL 3D __ a _ s
NEGA 40 u a a a a
NGB 50 u a a a a
NEG 00 60 70 u a a a a
NOP 12 -----
ORA 8A 9A AA BA _ a a 0 _
ORB CA DA EA FA _ a a 0 -
ORCC 1A *
PSHS 34 -----
PSHU 36 -----
PULS 35 -----
PULU 37 -----
ROLA 49 _ a a a a
ROLB 59 _ a a a a
204
Appendix !
ROL 09 69 79 _a a a a
RORA 46 _ a a _ a
RORB 56 _a a _ a
ROR 06 66 76 _ a a _ a
RTI 3B *
RTS 39 - ----
SBCA 82 92 A2 B2 u a a a a
SBCB C2 D2 E2 F2 u a a a a
SEX 1D _a a 0 _
STA 97 A7 B7 _ a a 0 _
STB D7 E7 F7 _ a a 0 _
STD DD ED FD _ a a 0 _
STS 10DF 10EF 10FF _ a a 0 _
STU DF EF FF _ a a 0 _
STX 9F AF BF _ a a 0 _
STY 109F 10AF 10BF _ a a 0 _
SUBA 80 90 AO BO u a a a a
SUBB co DO E0 F0 u a a a a
SUBD 83 93 A3 B3 _ a a a a
SWI 3F ---_ --
SWl2 103F - - - - -
SWl3 113F - - - - -
SYNC 13 -----
TFR 1F -----
TSTA 4D _ a a 0 _
TSTB 5D _a a 0 _
TST OD 6D 7D _a a 0 _
205
Language of the Dragon
Branch Instructions
206
Appendix I
Indirect
207
Language of the Dragon
Key
R = register
code
X = don't
care
Register Code X = 00 Y = 01 U = 10 5 = 1 1
208
Appendix II
DASM
The DASM assembler from Compusense has a number of features that
make it particularly suitable for the beginning assembly language
programmer. Available as a program cartridge it will assemble lines of 6809
assembly language embedded in a Dragon BASIC program. The machine
code so produced can be stored anywhere in memory but it is usual for DASM
to store it just above the memory used by BASIC (as with the BASIC
assembler). Since the text of the assembly language program is entered
exactly as if it formed part of a BASIC program, editing the text is carried out,
by the familiar but limited, EDIT command. DASM supports all of the 6809's
features including indirect addressing, Program Counter relative etc. It also
supports full address expressions, a range of constant types and the usual
pseudo ops. All labels in DASM must start with @ and so it is possible to
assembly and run any of the programs in this book without modification.
If you want to use a machine code monitor program to debug your
programs assembled with DASM, then Compusense have produced a simple
monitor called DEMON, available as a separate cartridge or together with
DASM on a single cartridge. This is a fairly limited but easy-to-use debugging
aid. It includes a memory dump, a register examine facility and break points
but not a disassembler.
In conclusion, DASM is easy to use an especially suited for situations in
which a little assembly language has to be mixed with BASIC.
DREAM
Dragon Data's own assembler is well described by its name. For the
serious assembly language programmer it is indeed a dream come true! The
209
Language of the Dragon
only problem is that it takes over the entire machine and substitutes its own
editor in place of BASICs crude but familiar editing commands. If you are
prepared to learn to use the DREAM editor then you will very quickly find it so
useful that you will be using it for other editing tasks! DREAM is available
either as a cassette or a cartridge and there is also a cartridge version called
ALLDREAM. This last package is by far the best investment if you are
planning to do much assembly language programming as it frees the largest
amount of RAM for use and also includes gives direct acess to the
DREAM BUG monitor program. This monitor is very sophisticated and as well
as the standard features such as memory and register examine, break points
etc it also contains a trace facility and a disassembler.
The DREAM assembler supports all the 6809's instructions and addressing
modes. It also supports the full range of address expressions and constants. It
also uses the most economical representation for constant offset indexed
mode even if this means making more than two passes through the program.
Only one label in any program to be assembled by DREAM can start with @
which is used as an optional marker for the start of the program. In other
words, to use DREAM to assemble the programs in this book REMOVE THE
@ SYMBOL FROM EVERY LABEL. Apart from this slight change you should
have no trouble using the DREAM assembler.
In conclusion, the DREAM assembler and the DREAM BUG monitor form
an ideal pair for anyone planning to do assembly language programming on a
regular basis.
210
Appendix I l l
1 R E M BASICASSEMBLER V10.1
5 CLEAR2000,&H6FFF
10 DATA LDA,&H86,&H96,&HA6,&HB6,-1
11 DATA LDB,&HC6,&HD6,&HE6,&H F6,-1
12 DATA STA,-1,&H97,&HA7,&HB7,-1
73 DATASTB,-1,&HD7,&HE7,&HF7,-1
14 DATA ADDA,&H8 B,&H9B,&HAB,&HBB,-1
15 DATA ADDB,&HCB,&HDB,&HEB,&HFB,-1
16 DATA RTS,-1,-1,-1,-1,&H39
17 DATAJMP,-1,&H0E,&H6E,&H7E,-1
18 DATAJSR,-1,&H9D,&HAD,&HBD,-1
19 DATA ANDA,&H84,&H94,&HA4,&HBB,-1
20 DATA ANDB,&HC4,&HD4,&HE4,&HF4 ,-1
21 DATA ORA,&H8A,&H9A,&HAA,&HBA,-1
22 DATA ORB,&HCA,&HDA,&HEA,&HFA,-1
23 DATA EORA,&H88,&H98,&HA8,&HB8 ,-1
24 DATA EORB,&HC8,&HD8,&HE8,&HF8,-1
25 DATA COMA,-1,-1,-1,-1,&H43
26 DATA COMB,-1,-1,-1,-1,&H53
27 DATA COM,-1,&H03,&H63,&H73,-1
28 DATA LSLA,-1,-1,-1,-1,&H48
29 DATA LSLB,-1,-1,-1,-1,&H58
30 DATA LSL,-1,&H08,&H68,&H78,-1
31 DATA LSRA,-1,-1,-1,-1,&H44
32 DATA LSRB,-1,-1,-1,-1,&H54
211
language of the Dragon
212
Appendix Ill
400 DATABRA,&H20,&H16
401 DATABCC,&H24,&H1 024
402 DATABCS,&H25,&H1025
213
language of the Dragon
403 DATABEO,&H27,&H1027
404 DATABGE,&H2C,&H102C
405 DATABGT,&H2E,&H102E
406 DATABHl,&H22,ffH1022
407 DATABHS,&H24,&H1 024
408 DATABLE,&H2F,&H102F
409 DATABLO,&H25,&H1025
410 DATABLS,&H23,&H1023
411 DATABLT,&H2D,&H102D
412 DATABMl,&H2B,&H102B
413 DATABNE,&H26,&H1026
414 DATABPL,&H2A,&H1 02A
415 DATABSR,&H8D,&H17
416 DATABVC,&H28,&H1028
417 DATABVS,&H29,&H1029
499 DATAZZZ,-1,-1
500 GOSUB1000
510 GOSUB2000
515 FORPASS= 1TO2
518 I =1:P = &H7000
520 GOSUB3000
530 GOSUB4000
540 GOSUB5000
550 IFPS =0THENGOSUB6000
555 IFPS> 0THENGOSUB6500
560 I = I + 1 :PS = 0
570 IFI< =TTHENGOTO520
575 PRINT
580 NEXTPASS
590 l = T:GOSUB1980
600 LC = 0 :GOTO515
1000 DIMA$(150),C(5),T$(50),T(50)
1010 1=0
1020 P = &H7000
1030 LC = 0
1040 RETURN
214
Appendix Ill
2200 CLS
2210 PRINT@76, " E D IT"
2220 PRINT
2230 PRINTTAB(10);"SELECT ONEOF"
2240 PRINT
2250 PRINTTABIB);"LIST PROGRAM....1 "
2260 PRINTTABl8I;"LISTTOPRINTER.2"
2270 PRINTTABl8);"ADDTO PROGRAM.. 3"
2280 PRINTTABIB);"DELETE LINES ... .4"
2290 INPUTED
2300 IF ED< 1 ORED>4THEN GOTO2000
2310 ONED GOTO2400,2400,2500,2700
2400 CLS
2405 I F l = 0THEN GOTO1 980
2410 FOR K = 1 TOI
2420 I F ED= 1 THEN PRINT K;":";TABl4I;A$(K) ELSE
PRINT jl -2 ,K;" :";TAB(4);A$(K)
2430 NEXTK
2440 GOTO 1980
215
Language of the Dragon
2700 INPUT"FIRSTLINETODELETE";FL
2710 INPUT"LASTLINETODELETE";LL
2720 IFLL< FLTHENPRINT'NOTDELETED":GOTO1 980
2730 FOR K = LL + 1 TOJ
2740 A$(FL+ K-LL-1 ) = A$1K)
2750 NEXTK
2760 I= 1-I LL-FL+ 1 ):PRINT"DELETED"
2770 GOTOl 980
2800 INPUT"SCREEN(0)ORPRINTER(1)";PRT
2810 T=I
2820 PRT = PRT*2
2830 RETURN
2850 INPUT'FILENAME";F$
2860 PRINT'PRESSPLAYANDRECORD"
2870 PRINT"PRESSANYKEYWHENREADY"
2880 IFINKEY$ = ""THENGOTO2880
2890 OPEN"O", lf-1 ,F$
2900 FOR K = 1 TOl :PRINTlf-1 ,A$(K):NEXTK
2910 CLOSE lf-1 :GOTO1 980
216
Appendix Ill
2920 INPUT"FILENAME";F$
2930 PRINT"PRESSPLAY"
2940 OPEN"l", jl-1,F$
2950 1 = 0
2960 IFEOF(-1 )THENCLOSEJl-1 :GOTO1980
2970 I= I+ 1 :INPUTJl-1,A$11)
2980 GOTO 2960
2990 CLS:EXEC&H7000
2995 GOTO 1 980
3000 J = l
301 0 IFMID$(A$11),j, 1 ) = ""THENJ = J + 1 :GOTO301 0
3020 M$= MID$IA$11),J, 1 )
3030 J = J + l
3040 IF J< = LENIA$(I)) THEN IF MID$(A$(1),J, 1 )< > " " THEN
M$ = M$ + MID$IA$(1),J, 1 ) :J = J + 1 :GOTO3040
3050 J = J + l
3060 IFLEFT$(M$, 1 ) = "@"THENGOTO3500
3070 RETURN
3500 S$ = M$
351 0 GOSUB7000
3520 IFF>0ANDPASS = l THENERR =2:GOT09000
3525 IFF> 0ANDPASS = 2THENGOTO301 0
3530 LC = LC + l
3540 T$(LC) = M $
3550 TI LC) = P
3560 GOTO3010
4000 RESTORE
4001 IFM$ = "EOU"THENPS = 1 :RETURN
4002 IFM$ = "RMB"THENPS = 2:RETURN
4003 IFM$ = "FCB"THENPS = 3:RETURN
4004 IFM$ = "FDB"THENPS =4: RETURN
4009 IF(LEFT$IM$, 1 ) = "B"ANDLEFT$IM$,3)< > "BIT")OR
LEFT$(M$,2) = "LB"THENGOTD4500
401 0READC$
401 5 FORK= 1 TO5:READC( K):NEXTK
4020 IFC$ = "ZZZ"THENI = I + 1 :ER = 1 :GOTO9000
4030 FC$= M$THENRETURN
4040 GDTD 401 0
217
Language of the Dragon
4500 READC$
4510 FOR K = 1 T05:READC(K):NEXTK
45i0 IFC$< > "ZZZ"THENGOT04500
4530 IF LEFT$(M$, 1) = "L" THEN M$ = RIGHT$(M$,3): BR = 2 ELSE
BR = 14535TYPE = BR
4540 READC$
4550 FORK = 1 T02:READCIKl:NEXTK
4560 IFC$= "ZZZ"THENI = I + 1 :ER = 1 :GOT09000
4570 IFC$ = M$THENRETURN
4580 GOT04540
218
Appendix /JI
219
Language of the Dragon
5800 TYPE = 3
5810 L$= MID$(A$(1},K-1 , 1 }
5820 OF=0
5830 IFL$= "A"THENO F = &H86
5840 IFL$ = "B"THENOF = &H85
5850 lFL$ = "D"THENOF = &H8B
5860 L$ = MID$IA$(1},K + 1 , 1 )
5870 IFL$= "-"THENL$ = MID$(A$(1 } , K + 2, 1 }:OF = &H82
5880 IFL$= "-"THENL$ = MID$(A$(1},K + 3, 1 }:OF= &H83
5890 RF=0
5900 IFL$ = "Y"THENRF = 1
5901 IFL$= "U"THENRF = 2
5902 IFL$= "S"THENRF = 3
5910 IFMID$(A$(1}, K +2,1} = " + "THENOF= &H80
5920 IFMID$(A$(1},K + 2,2} = " + + "THEN O F = &H81
5930 IFOF< > 0THENAF$= STR$(RF + OF}:RETURN
5950 O F = &H89 + R F
5955 AF$ = " " + AF$
5960 A = VAL(AF$}
5970 IA = 1
5980 IFA> =0THENRETURN
5990 AF$ = STR$(65536 + A}
5995 RETURN
220
Appendix. JI/
221
Language of the Dragon
7000 K=l
7010 IFK> LCTHEN F = 0 :RETURN
7020 IFT$1KI = S$THENF = K:RETURN
7030 K=K+l
7040 GOTO 7010
222
Appendix IV
ROM Subroutines
Address Description
JSR $801 5 Turn on cassette relay
JSR $8018 Turn off cassette relay
JSR ($A008) Write block of data to cassette - $7C = Block type 0 is
fileheader
1 is data
FF is end of file
$7D = Number of bytes to be written $7E/F =
Address of start of data to be written
JSR $8021 Prepares cassette for data input
JSR ($A006) Reads in data from cassette (used following JSR
$8021 )-
$7E/ F = Addressoflocationwheredatawillbestored
$81 Error code, clear if no error
JSR $8006 Reads keyboard, returns ASCII code of key pressed in
A register. If no key is pressed A = 0
JSR $801 2 Updates the four joystick reading stored in $15A to
$ 15D
JSR $800C Writes the character whose ASCII code is in the A
registertothescreen-
&88/89 contain the address of the next screen location
the $800C will use
JSR $800F As for $800C but character is sent to printer
223
Answers to Micro Projects
Chapter Two
11
address data
28672 146 LDA 200
28673 200
28674 1 53 ADDA201
28675 201
2) After running the program, memory location 200 still contains 56 and
memory location 201 still contains 4. The result of the addition, that is 60, is
stored in the A register.
Chapter Three
21
al $01 oo = 0000 0001 0000 0000
bi $1000 = 0001 0000 0000 0000
c) $7FFF = 01 1 1 1111 1111 1111
d) $7FFF = 1111 1111 1111 1 1 11
$FFFF is the highest address that you can use on the Dragon and $7 FFF is the
highest address occupied by RAM.
224
Answers to Micro Projects
3a) Trying to store something using immediate addressing doesn't make any
sense.
b) $7FFF is too large to be loaded into the A register as the result of
immediate addressing.
41
7000 86 10
7002 88 7FFF
7005 87 7FFF
7008 39
The program adds $10 to the contents of memory location $7FFF and then
stores the result back in $7FFF.
Chapter Four
11
585 GOSU8 6900
6900 PRINT
6910 FOR K = 1 TO LC
6920 PRINT T$(KI;" = ";T(kl
6930 NEXT K
6940 RETURN
21
@INPUT EQU $8006
@PRINT EQU $800C
@LOOP JSR @INPUT
JSR @INPUT
JMP @LOOP
Chapter Five
11
LDA @DATA
ORA * $80
ANDA *$F1
STA @DATA
225
Language of the Dragon
21
@LOOP COM @FLIPPER
JMP @LOOP
31
LSLA
ROLB
LSLA
ROLB
LSLA
ROLB
LSLA
ROLB
This program is based on the fact that LSLA followed by ROLB will move b7 in
the A register into b1 in the B register using the C bit as a temporary store.
41
@START LDA @DATA1
ANDA @DATA2
STA @DATA3
RTS
@DATA1 FCB 23
@DATA2 FCB 44
@DATA3 FCB 0
Notice that the values following the FCB's constitute whatever data you
actually wanted to AND �ogether.
Chapter Six
LDA @DATA1
ADDA @DATA2
STA @ANS
RTS
This program would be capable of adding together 200 and 50 giving the
answer 250 in memory location @ANS.
226
Answers to Micro Projects
31
LDA @NUM
ASLA
ASLA
ASLA
ADDA @NUM
STA @ANS
This program will multiply the two's complement number in @NUM by nine
by first performing three arithmetic shift lefts and then adding the original
number to the result. As each shift left is equivalent to multiplication by 2, the
final result stored in @ANS is 8 times the contents of @NUM plus the
contents of @NUM or, in other words, 9 times the contents of @NUM as
required.
41
LDB @LITTLE
SEX
SUBD @BIG
The eight-bit value is loaded into the B register and then sign extended into
the A register to give a correct two's complement 16-bit number in the D
register. The SUBD instruction is then used to subtract the 1 6-bit value giving
the result, which is also 16 bits, and so takes two memory locations to store.
Chapter Seven
11
@ORCC $04
ANDCC $FE
227
Language of the Dragon
2)
LDB 10
@LOOP ..............
instructions within the loop
..............
DECB
CMPB 1
BGE @LOOP
3)
LDA @DATA1
ADDA @DATA2
BCS @ERJMP
JSR @RESULT
..............
rest of program
..............
@ERJMP JSR @ERROR
..............
rest of program
..............
Following a simple binary addition the carry bit is set if the result is out of
range.
4) The only change that is necessary is to change the BCS @ERJMP to BVS
@ERJMP. For two's complement addition the V bit is set following an
overflow.
Chapter Nine
1)
@DELAY LDX @TIME
@DLOOP LEAX -1
BNE @DLOOP
RTS
228
Answers to Micro Projects
21
10 CLEAR 1 000,&H6FFF
20 POKE &H7EFF,255
30 FOR 1 = 1 TO 255
40 POKE &H7F00 + I - 1 ,RND(64I - 1
50 NEXT I
60 POKE &H7EFE,RND(255I
70 POKE &H7EFD,RND(255I
80 EXEC &H7000
90 STOP
where all of the values of the sound generator program are set randomly.
Chapter Ten
1)
@DELAY SYNC
RTS
229
Index
A BHI 1 07
ABX 1 57 BHS 107
Accumulator 8 Binary coded decimal 86
Accumulator Offset 1 52 BITA, BITB 112
ADC 125 Bit manipulation 58
ADDA, ADDB 19 Bitwise operations 54
ADDD 74 BLE 105
Address 21 BLS 108
Addressing 21 BLT 105
Addressing mode 22 BLU 108
Addressing register BMI 103
(see pointer register) BNE 103
ANDA, ANDB 53 BPL 103
ANDCC 101 BRA 92
Apple 2 Branch Instructions 91
A register 8 B register 8
Arithmetic 71 BSR 112
ASR, ASRA, ASRB 85 BVC 104
'Auto' indexing 1 54 BVS 1 04
Byte 22
B
BASIC 1 C
BCC 104 Carry bit 100
BCS 1 04 CLR, CLRA, CLRB 78
BEQ 103 CMP 109
BGE 105 CMPS 148
BGT 105 CMPU 148
230
Index
CMPX 148 H
CMPY 148 Hexadecimal 24
COM, COMA, COMB 56 HEX$ 24
Complement, see COM H lhalf)bit 99
Conditional branch 98
Condition code 98
Constant offset indexing 149 1
CWAI 186 1 bit 184
1mmediateaddressing 34
D INC, INCA, INCS 78
DAA 87 Indexed addressing 146
DEC, DECA, DECB 78 Index register 148
Delay loop 136 Indirection 158
Direct addressing 22,163 IRQ 181
DP (Direct Pagel 147, 163 Interrupt 177
DRegister 74 Interrupt handler 182
E
J
Editor 117
E (Entire) bit 184 JMP 3
Effective address 156 JSR 47
EORA,EORB 55
EQU 49 L
Exclusive - or, see EOR Label 34
EXG 150 LBA 95
Extended addressing 26 LBPL 102
Extended precision 80 LBSR 112
LDA 10
F LDB 10
FAC 198 LDD 79
F bit 184 LOS 148
FCB 66 LDU 148
FDB 66 LOX 147
FIRQ 182 LDY 148
Floating point 72 LEA, LEAX, LEAU, LEAY 156
Floating point binary 198 LIFO 178
Forward jump 43 Load 10
Logical operations 53
G LSL, LSLA, LSLB 62
GOTO 37 LSR, LSRA, LSRB 62
231
Language of the Dragon
232
Index
V Y
V (oVerflowl bit 100 Y register 147
w Z
White noise 173 Z (zerol bit 99
233