Leventhal-6809AssemblyLanguageProgramming Text
Leventhal-6809AssemblyLanguageProgramming Text
% H
I 00
o
CO
>
8
3
CD
I
rn
~o
TO
O
CD
gg
6809
Assembly Language
Programming
Lance A. Leventhal
OSBORNE/McGraw-Hill
Berkeley, California
Published by
OSBORNE/McGraw-Hill
630 Bancroft Way
Berkeley, California 94710
U.S. A
For information on translations and book distributors outside of the U. S. A.
please write OSBORNE/McGraw-Hill at the above address.
0-5 23S
Mr. Curt Ingraham, Ms. Susanna Jacobson, Ms. Denise Penrose, and Ms. Janice Enger
of Osborne/McGraw-Hill contributed greatly to this project; Susanna Jacobson and Curt
Ingraham insisted on a high level of clarity and accuracy. Mr. Lothar Stern and Mr.
Marshall Rothen of Motorola's Technical Information Center (Phoenix) were very
generous in providing materials. Others who helped include Ms. Marielle Carter, Mr.
Romeo Favreau, and Mr. Gary Hankins of Sorrento Valley Associates; Mr. Michael
Lehman and Mr. Winthrop Saville of MT MicroSystems; and my wife Donna, who has
been both patient and understanding.
Special thanks go to Mr. Terry Ritter of Motorola (Austin, Texas), the original
architect of the 6809 microprocessor, who was kind enough to review the manuscript.
Also Dr. Jack Lipovski of the University of Texas at Austin provided me with a
preliminary version of his 6,809-based book Microcomputer Interfacing: Principles and
Practices (Lexington Boqp«< Lexington, Mass., 1980); it is an excellent book and I have
borrowed heavily from the idea's in it.
Mr. Allan Robbins, P.E., of SDS Technical Services, Ltd., Winnepeg, Canada,
contributed material for Chapter 3, Chapter 22, and the appendices.
I would like to take this opportunity to thank those who have reviewed previous
books in this series. In particular, I should mention Mark Bernstein, Jim Butterfield, Art
Childs, James Demas, and Philip Hooper. Of course, my initial reaction to their negative
comments was defensive. However, after some complaining and some prodding from
my editors, I have responded to their criticism in this book. I have revised several chap-
ters considerably and I have stressed clear, concise explanations and interesting exam-
ples. Reviewing is a thankless job, so I want these people to know that I have learned
from their efforts.
This book is dedicated to the friends I made along South Highway 101 in Solana
Beach, California: Don and Hazel Cahoon, Lou and Marge DiCarlo, and Bob and June
Vallery.
— Lance A. Leventhal
Dr. Leventhal has authored four previous books in this series and has just begun work
on a new series, Some Common Assembly Language Programs. He received a B.A.
degree from Washington University in St. Louis, and M.S. and Ph.D. degrees from the
University of California at San Diego. He is a member of SCS, ACM, IEEE, and the
IEEE Computer Society.
Contents
2. Assemblers
Features of Assemblers 2-1
Types of Assem biers 2-15
Errors 2-16
Loaders 2-17
6. Character-Coded Data
Handling Data in ASCII 6-1
Program Examples 6-3
Problems 6-13
7. Code Conversion
Program Examples 7-2
Problems 7-10
8. Arithmetic Problems
Program Examples 8-2
Problems 8-16
1 2. Input/Output Considerations
I/O Device Categories 12-2'
1 5. Interrupts
Characteristics of Interrupt Systems 15-1
6809 Interrupt System 15-3
6820 PIA Interrupts 15-8
6850 ACIA Interrupts 15-8
6809 Polling Interrupt Systems 15-9
6809 Vectored Interrupt Systems 15-10
Communications Between Main Program and Service Routines 15-10
Enabling and Disabling Interrupts 15-11
Changing Values in the Stack 15-13
Interrupt Overhead 15-15
Program Examples 15-15
More General Service Routines 15-30
Problems 15-31
18. Documentation
Self-Documenting Programs 18-1
Comments 18-2
Flowcharts as Documentation 18-7
Structured Programs as Documentation 18-7
Memory Maps 18-7
Parameter and Definition Lists 18-8
Library Routines 18-9
Total Documentation 18-12
19. Debugging
Simple Debugging Tools 19-2
Advanced Debugging Tools 19-8
Debugging With Checklists 19-10
Looking for Errors 19-11
Examples 19-17
20. Testing
Selecting Test Data 20-2
Examples 20-3
Rules for Testing 20-4
Conclusions 20-4
Appendices
A. Summary of the 6809 Instruction Set
Index
1
Program Examples
Fundamental Concepts
This book describes assembly language programming. It assumes that you are
familiar with An Introduction to Microcomputers: Volume 1 — Basic Concepts
(Berkeley: Osborne/McGraw-Hill, 1980). Chapters 6 and 7 of
that book are
especially relevant. This book does not discuss the general features
of computers,
microcomputers, addressing methods, or instruction sets; you should refer
to An
Introduction to Microcomputers: Volume 1 for that information.
The chapters in this section provide basic information on assembly language in
general and the 6809 in particular. Chapter 1 discusses the purpose of
assembly
language and compares it with higher-level computer languages. Chapter
2 discusses as-
semblers and, briefly, loaders. Chapter 3 describes the architecture of
the 6809
microprocessor, compares it with similar processors, and discusses important
features of
Motorola's 6809 assemblers.
A computer program is ultimately a series of numbers and therefore has very little
meaning to a human being. In this chapter we will discuss the levels of human-like
language in which a computer program may be expressed. We will further discuss the
reasons for and uses of assembly language, which is the subject of this book.
Binary Instructions
An instruction is a binary digit pattern — it must be available at the data
inputs to the microprocessor at the proper time in order to be interpreted as an
instruction. For example, when the 6809 microprocessor receives the 8-bit binary pat-
tern 01001111 as the input during an instruction fetch operation, the pattern means:
The microprocessor (like any other computer) only recognizes binary patterns as
instructions
ctions or data; it does not recognize words or octal, decimal, or hexadecimal num-
bers.
A COMPUTER PROGRAM
A program is a series of instructions that causes a computer to perform a partic-
ular task.
Actually, a computer program includes more than instructions; it also contains
the data and memory addresses that the microprocessor needs to accomplish the tasks
defined by the instructions. Clearly, if the microprocessor is to perform an addition, it
must have two numbers to add and a place to put the result. The computer program
must determine the sources of the data and the destination of the result as well as the
operation to be performed.
All microprocessors execute instructions sequentially unless an instruction
changes the order of execution or halts the processor. That is, the processor gets its next
instruction from the next higher memory address unless the current instruction
specifically directs it to do otherwise.
is a set of binary numbers. For example, this is a
Ultimately, every program
6809 program that adds the contents of memory locations 0060 16 and 0061 16 and
places the result in memory location 0062 16 :
10110110
00000000
01100000
10111011
00000000
01100001
10110111
00000000
01100010
This is a machine language, or object, program. If this program were entered into the
memory of a 6809-based microcomputer, the microcomputer would be able to execute it
directly.
1. The programs are difficult to understand or debug. (Binary numbers all look
the same, particularly after you have looked at them for a few hours.)
2. The programs are slow to enter since you must set a front panel switch for
each bit and load memory one byte at a time.
3. The programs do not describe the task which you want the computer to per-
form in anything resembling a human-readable format.
5. The programmer often makes careless errors that are very difficult to locate
and correct.
For example, the following version of the addition object program contains a
single bit error. Try to find it:
10110110
00000000
01100000
10111011
00000000
01110001
10110111
00000000
01100010
Although the computer handles binary numbers with ease, people do not. People
programs long, tiresome, confusing, and meaningless. Eventually, a pro-
find binary
grammer may start remembering some of the binary codes, but such effort should be
spent more productively.
0000 O
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
A 1010 10
B 1011 11
C 1100 12
D 1101 13
E 1110 14
F 1111 15
1-4 6809 Assembly Language Programming
Hexadecimal Loader
These repetitive, grueling tasks are, however, perfect jobs for a computer. The
computer never gets tired or bored and never makes silly mistakes. The idea then is to
write a program that accepts hexadecimal numbers, converts them into binary num-
bers, and places them in memory. This is a standard program provided with many
microcomputers; it is called a hexadecimal loader.
The hexadecimal loader is a program like any other. It occupies memory space. In
some systems, it resides in memory just long enough to load another program; in
others, it occupies a reserved, read-only section of memory. Your microcomputer may
not have bit switches on its front panel; it may not even have a front panel. This reflects
the machine designer's decision that binary programming is not only impossibly tedious
but also wholly unnecessary. The hexadecimal loader in your system may be part of a
larger program called a monitor, which also provides a number of tools for program
debugging and analysis.
A hexadecimal loader certainly does not solve every programming problem. The
hexadecimal version of the program is still difficult to read or understand; for example,
it does not distinguish operations from data or addresses, nor does the program listing
provide any suggestion as to what the program does. What does B6 or 3F mean?
Memorizing a card full of codes is hardly an appetizing proposition. Furthermore, the
codes will be entirely different for a different microprocessor and the program will
require a large amount of documentation.
code. The instruction code name is called a "mnemonic" or memory jogger. The
Introduction to Assembly Language Programming 1 -5
Devising Mnemonics
In fact, all microprocessor manufacturers (they cannot remember hexadecimal
codes either) provide a set of mnemonics for the microprocessor instruction set. You do
not have to abide by the manufacturer's mnemonics; there is nothing sacred about
them. However, they are standard for a given microprocessor, and therefore under-
stood by all users. These are the instruction codes that you will find in manuals, cards,
books, articles, and programs. The problem with selecting instruction mnemonics is that
not all instructions have "obvious" names. Some instructions do (for example, ADD,
AND, OR), others have obvious contractions (such as SUB for subtraction, XOR for
exclusive-OR), while still The result is such mnemonics as WMP,
others have neither.
PCHL, and even SOB. Most manufacturers come up with some reasonable names and
some hopeless ones. However, users who devise their own mnemonics rarely do much
better.
Along with the instruction mnemonics, the manufacturer will usually assign
names to the CPU registers. As with the instruction names, some register names are
obvious (such as A for Accumulator) while others may have only historical significance.
Again, we will use the manufacturer's suggestions simply to promote standardization.
Standard Mnemonics
There is a proposed standard set of assembly language mnemonics. 1 The
amount of use thatit will receive is uncertain, but it should at least serve as a basis for
comparing instruction sets and for selecting mnemonics for future processors.
LDA $0060
ADDA $0061
STA $0062
The program is still far from obvious, but at least some parts are comprehensible.
ADDA is a considerable improvement over BB. LDA and STA suggest loading and
storing the contents of an accumulator. We now see that some lines are operations and
others are data or addresses. Such a program is an assembly language program.
The following table illustrates the hand assembly of the addition program:
Early assemblers did little more than translate the mnemonic names of instruc-
tions and registers into their binary equivalents. However, most assemblers now pro-
vide such additional features as:
• Allowing the user to assign names to memory locations, input and output
devices,and even sequences of instructions
• Converting data or addresses from various number systems (for example,
decimal or hexadecimal) to binary and converting characters into their ASCII
or EBCDIC binary codes
• Telling the loader program where in memory parts of the program or data
should be placed
• Allowing the user to assign areas of memory as temporary data storage and to
place fixed data in areas of program memory
Introduction to Assembly Language Programming 1-7
• Allowing the user to control the format of the program listing and the input
and output devices employed
Choosing an Assembler
All of these features, of course, involve additional cost and memory. Microcom-
puters generally have much simpler assemblers than do larger computers, but the ten-
dency is always for the size of assemblers to increase. You will often have a choice of as-
semblers. The important criterion is not how many off-beat features the assembler has,
but rather how convenient it is to use in normal practice.
Lack of Portability
In addition, assembly language programs are not portable. Each microcomputer
has its own assembly language which reflects its own architecture. An assembly
language program written for the 6809 will not run on a 6502, Z80, 8080, or 3870
microprocessor. For example, the addition program written for the 8080 would be:
LDA 60H
MOV B,A
LDA 61H
ADD B
STA 62H
The lack of portability not only means
you will not be able to use your assem-
that
bly language program on a different microcomputer, but also that you will not be able to
use any programs that were not specifically written for the microcomputer you are using.
This is a particular drawback for microcomputers, since these devices are new and few
assembly language programs exist for them. The result, too frequently, is that you are
1-8 6809 Assembly Language Programming
on your own. If you need a program to perform a particular task, you are not likely to
find it in the small program libraries that most manufacturers provide. Nor are you likely
to find it in an archive, journal article, or someone's old program file. You will probably
have to write it yourself.
HIGH-LEVEL LANGUAGES
The solution to many of the difficulties associated with assembly language pro-
grams is to use, instead, "high-level" or "procedure-oriented" languages. Such
languages allow you to describe tasks in forms that are problem-oriented rather than
computer-oriented. Each statement in a high-level language performs a recognizable
function; it will generally correspond to many assembly language instructions. A
program called a compiler translates the high-level language source program into
object code or machine language instructions.
That is a lot simpler (and a lot shorter) than either the equivalent machine language pro-
gram or the equivalent assembly language program. Other high-level languages include
COBOL PASCAL (a language designed for structured pro-
(for business applications),
gramming), PL/I combination of FORTRAN and COBOL), APL and BASIC (popu-
(a
lar for time-sharing systems), and C (a systems-programming language developed at
does not include problem definition, program design, debugging, testing, or documen-
tation, all of which become simpler and faster. The high-level language program is, for
instance, partly self-documenting. Even if you do not know FORTRAN, you probably
could tell what the statement illustrated above does.
Machine Independence
High-level languages solve many other problems associated with assembly
language programming. The high-level language has its own syntax (usually defined by
a national or international standard). The language does not mention the instruction
Introduction to Assembly Language Programming 1-9
set, registers, or other features of a particular computer. The compiler takes care of all
such details. Programmers can concentrate on their own tasks; they do not need a
detailed understanding of the underlying CPU architecture — for that matter, they do
not need to know anything about the computer they are programming.
Portability
Syntax
One obvious problem is that, as with assembly language, you have to learn the
"rules" or "syntax" of any high-level language you want to use. A high-level
language has a fairly complicated set of rules. You will find that it takes a lot of time just
to get a program that is syntactically correct (and even then it probably will not do what
you want). A high-level computer language is like a foreign language. If you have talent,
you will get used to the rules and be able to turn out programs that the compiler will
accept. Still, learning the rules and trying to get the program accepted by the compiler
does not contribute directly to doing your job.
Here, for example, are some FORTRAN rules:
Cost of Compilers
Another obvious problem is that you need a compiler to translate programs writ-
ten in a high-level language into machine language. Compilers are expensive and use a
large amount of memory. While most assemblers occupy 2K to 16K bytes of memory
(IK = 1024), compilers occupy 4K to 64K bytes. So the amount of overhead involved
in using the compiler is rather large.
1-10 6809 Assembly Language Programming
Inefficiency
• Special rules
• Extensive hardware and software support required
• Orientation of common languages to algebraic or business problems
• Inefficient programs
• Difficulty of optimizing code to meet time and memory requirements
• Inability to use special features of a computer conveniently
Introduction to Assembly Language Programming 1-11
Many of the high-level languages that exist do not conform to recognized stan-
dards, so the microprocessor user cannot expect to gain much program portability,
access to program libraries, or use of previous experience or programs. The main advan-
tages remaining are the reduction in programming effort, easier documentation, and the
smaller amount of detailed understanding of the computer architecture that is necess-
ary.
control information to output devices and receiving data and status information from
input devices. Often the control and status information consists of a few binary digits
with very precise hardware-related meanings. If you try to write a typical control pro-
gram in a high-level language, you may feel like someone who is trying to eat soup with
chopsticks. For tasks in such areas as test equipment, terminals, navigation systems,
signal processing, and business equipment, the high-level languages work much better
than they do in instrumentation, communications, peripherals, and automotive applica-
tions.
Applications better suited to high-level languages are those which require large
memories. If, as in a valve controller, electronic game, appliance controller, or small
instrument, the cost of a single memory chip is important, then the inefficient memory
use of high-level languages is intolerable. If, on the other hand, as in a terminal or test
equipment, the system has many thousands of bytes of memory anyway, this ineffi-
ciency is not as important. Clearly the size and volume of the product are important fac-
tors as well. A large program will greatly increase the advantages of high-level
languages. On the other hand, a high-volume application will mean that fixed software
development costs are not as important as memory costs that are part of each system.
• Low-volume applications
• Applications where the amount of memory required is already very large
• Applications involving more computation than input/output or control
• Compatibility with similar applications using larger computers
• Availability of specific programs in a high-level language which can be used in
the application
Other Considerations
Many other factors are also important, such as the availability of a large computer
for use in development, experience with particular languages, and compatibility with
other applications.
If hardware will ultimately be the largest cost in your application, or if speed is crit-
ical,you should favor assembly language. But be prepared to spend much extra time in
software development in exchange for lower memory costs and higher execution
speeds. If software will be the largest cost in your application, you should favor a high-
level language. But be prepared to spend the extra money required for the supporting
hardware and software.
Of course, no one except some theorists will object if you use both assembly and
high-level languages. You can write the program originally in a high-level language and
then patch some sections in assembly language. 10 " However, most users prefer not to
-
The rest of this book will deal exclusively with assemblers and assembly language
programming. However, we do want readers to know that assembly language is not the
only alternative. You should watch for new developments that may significantly reduce
programming costs if such costs are a major factor in your application.
REFERENCES
1. W. P. Fischer, "Microprocessor Assembly Language Draft Standard," Computer,
December 1979, pp. 96-109.
2. M. H. Halstead, Elements of Software Science, American Elsevier, New York, 1977.
4. M. Phister, Jr., Data Processing Technology and Economics, Santa Monica Publishing
Co., Santa Monica, Calif., 1976. Also available from Digital Press, Educational Ser-
vices, Digital Equipment Corp., Bedford, Mass.
5. Albrecht, Finkel, and Brown, BASIC for Home Computers, Wiley, New York, 1978.
11. D. B. Wecker et al., "High Level Design Language Develops Low Level
Microprocessor-Independent Software," Computer Design, June 1979, pp. 140-49.
2
Assemblers
FEATURES OF ASSEMBLERS
As we mentioned previously, today's assemblers do much more than translate
assembly language mnemonics into binary codes. But we will describe how an assem-
bler handles the translation of mnemonics before describing additional assembler
features. Finally we will explain how assemblers are used.
VAL1 RMB 1
VAL2 RMB 1
SUM RMB 1
The comment and label fields are optional. A programmer will assign a label to
a statement or add a comment as a personal convenience: namely, to make the pro-
gram easier to read and use.
Of course, the assembler must have some way of telling where one field ends
and another begins. Assemblers that use punched card input often require that each
field start in a specific card column. This is a "fixed format." However, fixed formats are
inconvenient when the input medium is paper tape; fixed formats are also a nuisance to
programmers. The alternative is a "free format" where the fields may appear anywhere
on the line.
Delimiters
If the assembler cannot use the position on the line to tell the fields apart, it must
use something else. Most assemblers use a special symbol or "delimiter" at the
beginning or end of each field. The most common delimiter is the space character.
Commas, periods, semicolons, colons, slashes, question marks, and other characters
which would not otherwise be used in assembly language programs also may serve as
delimiters. Table 2-2 lists standard 6809 assembler delimiters.
You will have to exercise a little care with delimiters. Some assemblers are
fussy about extra spaces or the appearance of delimiters in comments or labels. A
well-written assembler will handle these minor problems, but many assemblers are
not well-written. Our recommendation is simple: avoid potential problems if you can.
The following rules will help:
• Do not use extra spaces, particularly after commas that separate operands.
• Include standard delimiters even if your assembler does not require them.
Then it will be more likely that your programs are in correct form for another
assembler.
Assemblers 2-3
Labels
The label field is the first field in an assembly language instruction; it may be
blank. If a label is present, the assembler defines the label as equivalent to the address
into which the first byte of the object code resulting from that instruction will be loaded.
You may subsequently use the label as an address or as data in another instruction's
address field. The assembler will replace the label with the assigned value when creating
an object program.
Labels are most frequently used in Jump, Call, or Branch instructions. These
instructions place a new value in the Program Counter and so alter the normal sequen-
tial execution of instructions. JUMP 150 16 means "place the value 150, in the Program
6
Counter." The next instruction to be executed will be the one in memory location 150 16 .
The instruction JUMP START means "place the value assigned to the label START in
the Program Counter." The next instruction to be executed will be the one at the
address corresponding to the label START. Table 2-3 contains an example.
Why use a label? Here are some reasons:
• The assembler or loader can relocate the whole program by adding a constant
(a "relocation constant") to each address in which a label was used. Thus we
can move the program to allow for the insertion of other programs or simply to
rearrange memory.
• The program is easier to use as a library program; that is, it is easier for some-
one else to take your program and add it to some totally different program.
• You do not have to figure out memory addresses. Figuring out memory
addresses is particularly difficult with microprocessors which have instructions
that vary in length.
You should assign a label to any instruction that you might want to refer to later.
The next question is how to choose a label. The assembler often places some
restrictions on the number of characters (usually 5 or 6) the leading character (often ,
must be a letter), and the trailing characters (often must be letters, numbers, or one of a
few special characters). Beyond these restrictions, the choice is up to you.
Our own preference is to use labels that suggest their purpose, i.e., mnemonic
labels. Typical examples are ADDW
in a routine that adds one word into a sum, SRETX
in a routine that searches for the ASCII character ETX, or NKEYS for a location in data
memory that contains the number of key entries. Meaningful labels are easier to
2-4 6809 Assembly Language Programming
• (MAIN PROGRAM)
JUMP START
When the machine language version of this program is executed, the instruction JUMP
START causes the address of the instruction labeled START to be placed in the program
counter. That instruction will then be executed.
• Do not use labels that are the same as operation codes or other mnemonics.
Most assemblers will not allow this usage; others will, but it is confusing.
• Do not use labels that are longer than the assembler permits. Assemblers have
various truncation rules.
• Start each label with a letter. Such labels are always acceptable.
• Do not use labels that could be confused with each other. Avoid the letters I,
O, and Z and the numbers 0, 1, and 2. Also avoid things like XXXX and
XXXXX. There's no sense in tempting fate and Murphy's Law.
• When you are not sure if a label is legal, do not use it. You will not get any real
benefit from discovering exactly what the assembler will accept.
These are recommendations, not rules. You do not have to follow them but don't blame
us if you waste time on unnecessary problems.
operands, others (like an Addition or a Jump instruction) have one, while still others
(like a transfer between registers or a multiple-bit shift) require two. Some instructions
may even some computers have instructions (like Shift
allow alternatives; for example,
or Clear) which can either apply to the Accumulator or to a memory location. We will
not discuss how the assembler makes these distinctions; we will just notle that it must do
so.
ASSEMBLER DIRECTIVES
Some assembly language instructions are not directly translated into machine
language instructions. These instructions are directives to the assembler ; they assign
the program to certain areas in memory, define symbols, designate ai[eas of for RAM
temporary data storage, place tables or other fixed data in memory, allow references to
other programs, and perform minor housekeeping functions.
To use these assembler directives or pseudo-operations a programmer places the
directive's mnemonic in the operation code field, and, if the specified directive requires
it, an address or data in the address field.
DATA
EQUATE = ( ) or DEFINE
ORIGIN
RESERVE
Linking directives (used to connect separate programs) are:
ENTRY
EXTERNAL
Different assemblers use different names for those operations bijt their functions
are the same. Housekeeping directives include:
END
LIST
NAME
PAGE
SPACE
TITLE
PUNCH
We will discuss these pseudo-operations briefly, although the|ir functions are
usually obvious.
2-6 6809 Assembly Language Programming
The DATA directive allows the programmer to enter fixed data into program
memory. This data may include:
Lookup tables
Messages
Synchronization patterns
Thresholds
Names
Coefficients for equations
Commands
Conversion factors
Weighting factors
Characteristic times or frequencies
Subroutine addresses
Key identifications
Test patterns
Character generation patterns
Identification patterns
Tax tables
Standard forms
Masking patterns
State transition tables
The DATA directive treats the data as a permanent part of the program.
DZCON DATA 12
will place the number 12 in the next available memory location and assign that loca-
tion the name DZCON. Every DATA directive usually has a label, unless it is one of a
The data and label may take any form that the assembler permits.
series.
Most assemblers allow more elaborate DATA directives that handle a large
Assemblers 2-7
names may refer to device addresses, numeric data, starting addresses, fixed addresses,
etc.
The EQUATE directive assigns the numeric value in its operand field to the
Most assemblers will allow you to define one label in terms of another, for example:
The label in the operand field must, of course, have been previously defined. Often, the
operand field may contain more complex expressions, as we shall see later. Double
name assignments (two names for the same data or address) may be useful in patching
together programs that use different names for the same variable (or different spellings
of what was supposed to be the same name)
Note that an EQU directive does not cause the assembler to place anything in
memory. The assembler simply enters an additional name into a table (called a
"symbol table") which the assembler maintains. This table, unlike the mnemonic
table, must be in RAM since it varies with each program. The assembler always needs
some RAM to hold the symbol table; the more RAM it has, the more symbols it can
accept. This RAM in addition to any that the assembler needs as temporary storage.
is
When do you use a name? The answer is: whenever you have a parameter that
you might want to change or that has some meaning besides its ordinary numeric value.
We typically assign names to time constants, device addresses, masking patterns, con-
version factors, and the like. A name like DELAY, TTY, KBD, KROW, or OPEN not
only makes the parameter easier to change, but it also adds to program documentation.
We also assign names to memory locations that have special purposes; they may hold
data, mark the start of the program, or be available for intermediate storage.
What name do you use? The best rules are much the same as in the case of
labels, except that here meaningful names really count. Why not call the teletypewriter
TTY instead of XI 5, a bit time delay BTIME or BTDLY rather than WW, the number of
the "GO" key on a keyboard GOKEY rather than HORSE? This advice seems
straightforward, but a surprising number of programmers do not follow it.
Where do you place the EQUATE directives? The best place is at the start of
the program, under appropriate comment headings such as I/O ADDRESSES, TEM-
PORARY STORAGE, TIME CONSTANTS, or PROGRAM LOCATIONS. This
makes the definitions easy to find if change them. Furthermore, another
you want to
user will be able to look up all the definitions in one centralized place. Clearly this prac-
tice improves documentation and makes the program easier to use.
Definitions used only in a specific subroutine should appear at the start of the
subroutine.
2-8 6809 Assembly Language Programming
Still other ORIGIN statements may allow room for later insertions, place tables or data
in memory, or assign vacant RAM space for data buffers.
Program and data memory in
Some assemblers assume an origin of zero if the programmer does not put an ORG
statement at the start of the program. The convenience is slight; we recommend the
inclusion of an ORG statement to avoid confusion.
You can use the RESERVE directive to reserve memory locations in program memory
or in data memory; however, the RESERVE directive is more meaningful when applied
to data memory.
Assemblers 2-9
In reality, all the RESERVE directive does is increase the assembler's Location
Counter by the amount declared in the operand field. The assembler does not actually
produce any object code.
Note the following features of RESERVE:
1. The label of the RESERVE directive is assigned the value of the first
address reserved. For example, the pseudo-operation:
TEMP RESERVE 20
reserves 20 bytes of RAM and assigns the name TEMP to the address of the
first byte.
3. No data is placed in the reserved locations. Any data that, by chance, may be
in these locations will be left there.
Some assemblers allow the programmer to specify initial values for the
RESERVE area in RAM. We strongly recommend that you do not use this feature; it
assumes that the program (along with the initial values) will be loaded from an external
device (e.g., paper tape or floppy disk) each time it is run. Microprocessor programs, on
the other hand, often reside in non-volatile ROM and start when power comes on. The
RAM in such situations does not retain its contents, nor is it reloaded. Therefore,
always include instruction sequences to initialize RAM in your program; this will insure
that initialization occurs every time the program is executed and not just during load
time.
Linking Directives
We often want statements in one program or subroutine to use names that are
defined in a different assembly. Such uses are called "external references"; a special
linking program is necessary to actually fill in the values and determine if any names are
undefined or doubly defined.
The directive EXTERNAL, usually abbreviated EXT, signifies that the name
is defined elsewhere.
The directive ENTRY, usually abbreviated ENT, signifies that the name is
The precise way in which linking directives are implemented varies greatly from
assembler to assembler. We will not refer to such directives again, but they are very
• END, which marks the end of the assembly language source program.
• LIST, which tells the Assembler to print the source program. Some assemblers
2-10 6809 Assembly Language Programming
repetitive listings.
•
NAME or TITLE, which prints a name at the top of each page of the listing.
•
PAGE or SPACE, which skips to the next page or next line, respectively, and
improves the appearance of the listing, making it easier to read.
•
PUNCH, which transfers subsequent object code to the paper tape punch. This
pseudo-operation may in some cases be the default option and therefore
unnecessary.
•
All EQUATE directives must have labels; they are useless otherwise, since
the purpose of an EQUATE is to define its label.
•
DATA and RESERVE directives usually have labels. The label identifies the
first memory location used or assigned.
•
Other directives should not have labels. Some assemblers allow such labels,
but we recommend against their use because there is no standard way to
interpret them.
names for registers and instructions and may have other built-in names. We will now
Decimal Numbers
Most assemblers assume all numbers to be decimal unless they are marked
otherwise. So:
add 1QQ
• B or % for binary
•
O,®, Q, or C for octal (the letter O should be avoided because of the confusion
with zero)
Assemblers 2-11
Assemblers generally require hexadecimal numbers to start with a digit (for example,
0A36 instead of A36) in order to distinguish between numbers and names or labels. It is
good practice to enter numbers in the base in which their meaning is the clearest: that is,
decimal constants in decimal; addresses and BCD numbers in hexadecimal; masking
patterns or bit outputs in binary if they are short, and in hexadecimal if they are long.
Names
Names can appear in the operand field; they will be treated as the data that
they represent. Remember, however, that there is a difference between operands and
addresses. In a 6809 assembly language program the sequence:
FIVE EQU 5
ADDA FIVE
will add the contents of memory location 5 (not necessarily the number 5) to the con-
tents of the accumulator. A sequence which adds in the number 5 itself would be
EQU 5
ADDA #FIVE
The symbol # tells the assembler that the number represented by the name FIVE is the
value of the operand instead of its memory location.
JUMP *+6
causes a Jump to the memory location 6 bytes beyond the byte that contains the first
6 locations <
-Jump here
have difficulty determining exactly how far apart two assembly language statements are.
2-12 6809 Assembly Language Programming
Using offsets from the location counter therefore frequently results in errors that you
can avoid if you use labels.
Character Codes
Most assemblers allow text to be entered as ASCII strings. Such strings may be
surrounded either with single or double quotation marks; strings may also use a begin-
ning or ending symbol such as A or C. A few assemblers also permit EBCDIC strings.
We recommend that you use character strings for all text. It improves the clarity
and readability of the program.
CONDITIONAL ASSEMBLY
Some assemblers allow you to include or exclude parts of the source program,
depending on conditions existing at assembly time. This is called conditional assem-
bly; it gives the assembler some of the flexibility of a compiler. Most microcomputer
assemblers have limited capabilities for conditional assembly. A typical form is
IF COND
(CONDITIONAL PROGRAM)
Assemblers 2-13
If the expression COND is true at assembly time, the instructions between IF and
ENDIF (two pseudo-operations) are included in the program.
Typical uses of conditional assembly are:
Unfortunately, conditional assembly tends to clutter programs and make them difficult
MACROS
You will often find that particular sequences of instructions occur many times in a
source program. Repeated instruction sequences may reflect the needs of your program
logic, or theymay be compensating for deficiencies in your microprocessor's instruction
set. You can avoid repeatedly writing out the same instruction sequence by using a
"macro."
Macros allow you name to an instruction sequence. You then use
to assign a
the macro name program instead of the repeated instruction sequence.
in your source
The assembler will replace the macro name with the appropriate sequence of instruc-
tions. The shaded parts of Figure 2-1 illustrate the assembler's treatment of a macro in
an example program. Do not bother trying to figure out what the program or the instruc-
tions do; just observe that the assembler expands the macro MAC1 into the defined
sequence.
A macro resembles a subroutine because it is a shorthand reference to a fre-
quently used instruction sequence. However, macros are not the same as subroutines.
The code for a subroutine occurs once in a program, and program execution branches to
the subroutine. In contrast, the assembler replaces each occurrence of a macro name
with the specified sequence of instructions; therefore program execution does not
branch to a macro as it does to a subroutine. A macro name is a user-defined assembler
directive;it directs assembly rather than program execution.
Advantages of Macros:
• Shorter source programs
• Better program documentation
• Use of debugged instruction sequences. Once the macro has been debugged,
you are sure of an error-free instruction sequence every time you use the
macro.
• Easier changes. Change the macro definition and the assembler makes the
change for you every time the macro is used.
• Inclusion of commands, keywords, or other computer instructions in the basic
instruction set. You can use macros to extend or clarify the instruction set.
2-14 6809 Assembly Language Programming
Disadvantages of Macros:
• Since the macro is expanded every time it is used, memory space may be
wasted by the repetition of instruction sequences.
One problem is that variables used in a macro are only known within it (i.e., they are
local ratherthan global). This can often create a great deal of confusion without any gain
in return. You should be aware of this problem when using macros. 1
COMMENTS
All assemblers allow you to place comments in a source program. Comments
have no effect on the object code, but they help you to read, understand, and document
the program. Good commenting is an essential part of writing computer programs;
programs without comments are very difficult to understand.
We will discuss commenting along with documentation in a later chapter, but
here are some guidelines:
• Use comments to tell what application task the program is performing, not
how the microcomputer executes the instructions.
Assemblers 2-1
• Keep comments brief and to the point. Details should be available elsewhere
in the documentation.
• Comment all definitions, describing their purposes. Also mark all tables and
data storage areas.
• Leave yourself notes at points that you find confusing: for example,
"REMEMBER CARRY WAS SET BY LAST INSTRUCTION." If such
points get cleared up later in program development, you may drop these com-
ments in the final documentation.
A well-commented program is easy to use. You will recover the time spent in comment-
ingmany times over. We will try to show good commenting style in the programming
examples, although we often over-comment for instructional purposes.
TYPES OF ASSEMBLERS
Although
all assemblers perform the same tasks, their implementations vary
greatly. We not try to describe all the existing types of assemblers; we will merely
will
define the terms and indicate some of the choices.
A cross-assembler is an assembler that runs on a computer other than the one
for which it assembles object programs.
The computer on which the cross-assembler runs is typically a large computer
with extensive software support and fast peripherals — such as an IBM 360 or 370, a
Univac 1 108, or a Burroughs 6700. The computer for which the cross-assembler assem-
bles programs is typically a micro like the 6809 or 8080. Most cross-assemblers are writ-
ten in FORTRAN so that they are portable.
A self-assembler or resident assembleris an assembler that runs on the com-
puter for which assembles programs. The self-assembler will require some memory
it
ERRORS
Assemblers normally provide error messages, often consisting of a single coded
letter. Some typical errors are:
In interpreting assembler errors, you must remember that the assembler may get on the
wrong finds a stray letter, an extra space, or incorrect punctuation. Many as-
track if it
semblers will then proceed to misinterpret the succeeding instructions and produce
meaningless error messages. Always look at the first error very carefully; subsequent
ones may depend on it. Caution and consistent adherence to standard formats will elimi-
Assemblers 2-17
LOADERS
The loader is the program which actually takes the output (object code) from
the assembler and places it in memory. Loaders range from the very simple to the very
complex. We will describe a few different types.
A "bootstrap loader" is a program that uses its own first few instructions to
load the rest of itself or another loader program into memory. The bootstrap loader
may be in ROM, or you may have to enter it into the computer memory using front
panel switches. The assembler may place a bootstrap loader at the start of the object pro-
gram that it produces.
A "relocating loader" can load programs anywhere in memory. It typically loads
each program into the memory space immediately following that used by the previous
program. The programs, however, must themselves be capable of being moved around
in this way; that is, they must be relocatable. An "absolute loader," in contrast, will
always place the programs in the same area of memory.
A "linking loader" loads programs and subroutines that have been assembled
separately; it resolves cross-references — that is, instructions in one program that
refer to a label in another program. Object programs loaded by a linking loader must be
created by an assembler that allows external references. An alternative approach is to
separate the linking and loading functions and have the linking performed by a program
called a "link editor."
REFERENCES
1 A complete monograph on macros is M. Campbell-Kelly, An Introduction to Macros,
American Elsevier, New York, 1973.
This chapter outlines the 6809 processor's architecture and describes the syn-
tax rules of the Motorola assembler. Chapter 9 of An Introduction to Microcomputers:
Volume 2 — Some Real Microprocessors 1 describes the hardware aspects of the 6809
microprocessor, including its output signals and interfaces. This book considers the
6809 from the point of view of the assembly language programmer, to whom pins and
signals are irrelevant and microcomputers and minicomputers are essentially identical.
Later chapters of this book describe the 6809's stack and interrupt system in more
detail.
Tables 3-1 through 3-3 divide the 6809 instruction set into instructions that are
frequently used (Table 3-1), occasionally used (Table 3-2), and seldom used (Table
3-3). If you are an experienced assembly language programmer, you will probably not
find this division important;you may even disagree with it. However, if you are a
novice, we recommend that you write your first programs using only the frequently
used instructions (Table 3-1). This restriction will help you overcome the obstacle of
learning both the entire 6809 instruction set and the basic methods of assembly
language programming at the same time. Once you have mastered the concepts of as-
sembly language programming, you should start using other instructions (Tables 3-2
and 3-3).
3-2 6809 Assembly Language Programming
INC Increment by 1
JSR Jump to Subroutine
LD Load
LSR Logical Shift Right
PSH Push Data onto Stack
PUL Pull Data from Stack
ROL Rotate Left
ROR Rotate Right
RTS Return from Subroutine
ST Store
SUB Subtract
8 bits Accumulator A \
> Double Accumulator D
8 bits Accumulator B J
The 6809's Condition Code register contains five status flags, two interrupt
IRQ interrupt and one for the fast FIRQ interrupt), and
control bits (one for the regular
one bit used to differentiate between the regular and fast interrupts. The five status
flags are:
Carry/Borrow (C)
Overflow (O or V)
Zero (Z)
Sign (S or N for Negative)
Half-Carry (H)
The flags occupy the following bit positions in the Condition Code register:
7 6 5 4 3 2 1 -^ Bit No.
E is the entire flag used to differentiate between regular and fast interrupts, F is the fast
interrupt mask bit, and I is the regular interrupt mask bit.
3-4 6809 Assembly Language Programming
6809 REGISTERS
The two accumulators, A
and B, are both primary accumulators. The only
instructions that treat the accumulators differently are ABX (Add Accumulator B to
Index Register X), DAA (Decimal Adjust Accumulator A), and SEX (Sign Extend
Accumulator B into Accumulator A).
The two 8-bit Accumulators A and B can be referred to as a single 16-bit Double
Accumulator D. Within D, A contains the most significant bits and B the least signifi-
cant bits. The 6809 has special instructions for loading (LDD), storing (STD), adding
(ADDD), comparing (CMPD), and subtracting (SUBD) the Double Accumulator D.
Index Registers X and Y are typical microcomputer index registers, as de-
scribed in An Introduction to Microcomputers: Volume I. 2 The X register is preferred over
the Y register only because a few operation codes (such as CMP, LD, and ST) execute
more slowly when applied to Y than when applied to X.
Stack Pointer U is a cross between the typical microcomputer index register
and the typical microcomputer stack pointer as described in An Introduction to
Microcomputers: Volume 1. Registers may be pushed onto or pulled from the User Stack
(indexed by the User Stack Pointer) However, the processor does not employ the User
.
Stack to store subroutine return addresses or the status of interrupted tasks; the pro-
cessor uses only the Hardware Stack for those purposes.
The 6809 has a Stack implemented in memory and indexed by the Hardware
Stack Pointer S as described in Volume 1 of An Introduction to Microcomputers. The
instruction set allows S, as well as U, to be used as a data counter or index register.
Memory reference instructions make it easy to store the contents of either
stack pointer or either index register in read/write memory. By assigning some
memory locations on the base (direct) page as storage for these four address registers,
you can put them all to multiple use. Another easy storage method is pushing the
registers onto a stack.
The program counter is a typical program counter, as described in Volume 1 of
An Introduction to Microcomputers.
The Direct Page Register DP generalizes the concept of a base page as described
in An Introduction to Microcomputers: Volume I. This register provides the eight most
significant bits of a 16-bit address in the direct (base page) addressing mode. In most
microprocessors (including the 6800), the base page is always page zero. The 6809
maintains compatibility with this concept by clearing the Direct Page register on hard-
ware Reset. The Direct Page register allows the programmer to move the base page any-
where in memory and thus take advantage of short paged addresses without being
limited to the first 256 bytes of memory. Different programs can have different base
pages, thus both making it unnecessary to apportion page zero and reducing the chance
of interference.
6809 FLAGS
The Carry flag holds the carry from the most significant bit produced by
arithmetic operations or shifts. Like most microprocessors, the 6809 inverts the actual
carry after subtraction so that the Carry flag also acts as a Borrow. The 6809 multiplica-
tion instruction, MUL, affects the Carry flag in yet another way: Carry represents bit 7
of the 16-bit result. This makes rounding to an 8-bit result very simple.
6809 Machine Structure and Assembly Language 3-5
The Zero flag is standard. It is set to 1 when any operation produces a zero
result. It is set to when any operation produces a non-zero result.
The Sign (Negative) flag is standard. It takes on the value of the most signifi-
cant bit of any result. Thus, a Sign flag value of 1 identifies a negative result and a
Sign flag value of identifies a positive result if the standard twos complement nota-
tion is being used. The Sign
flag will be set or reset on the assumption that you are using
signed binary arithmetic. you are not using signed binary arithmetic, you can ignore
If
the Sign flag or you can use it to identify the value of the most significant bit of the
result.
The Half-Carry flag holds any carry from bit 3 to 4 resulting from the execution
of an (ADC or ADD). The purpose of this flag is to simplify
8-bit addition instruction
Binary-Coded-Decimal (BCD) operations. This is the standard use of a Half-Carry flag
as described in An Introduction to Microcomputers: Volume 1, Chapter 4 (the flag is re-
ferred to there as an "intermediate carry").
The Overflow flag represents standard arithmetic overflow as described in
Volume 1 of A n Introduction to Microcomputers; that is, the flag is set when an
arithmetic result greater in magnitude than can be represented in the register. A
is
processor implements this function by setting the overflow flag when the carry out of the
most significant bit is different from the carry out of the next most significant bit; that is,
an overflow is the exclusive-OR of the carries into and out of the sign bit. In the 6809,
logical operations clear the Overflow flag, as do loads and stores.
The I and F flags are standard interrupt disable or interrupt mask flags. When I or
F is 1, interrupts are disabled from the corresponding source (IRQ or FIRQ). When I
or F is 0, the corresponding interrupt is enabled.
The E (or Entire) flag differentiates between regular interrupts and fast inter-
rupts. E is when any interrupt occurs that stacks the entire set of registers; E is
set to 1
set to when an FIRQ occurs, stacking only the program counter and Condition Code
register. The E flag thus allows proper unstacking of the registers by the RTI (return
from interrupt) instruction.
The change until the processor executes an instruction that
flags do not
modifies them. Logical instructions, for example, do not affect the Carry or Half-Carry,
but they do affect the Sign, Zero, and Overflow flags. Any of the flags can be specifically
set or cleared by means of an ORCC or ANDCC instruction with the appropriate mask.
You must use the bit positions shown earlier to create the mask; executing an ORCC
with a 1 in a particular bit position will set a flag, while executing an ANDCC with a in a
particular bit position will clear a flag.
6809 literature refers to the Sign flag as a Negative flag and uses the symbol N for
it. We will follow this convention to be compatible with the literature and to avoid con-
fusion with the Hardware Stack Pointer (or S register). We will also follow the 6809
Overflow flag by the symbol V (O leads to continual confu-
literature in referring to the
sion) and the Half-Carry flag (sometimes called an Auxiliary or Intermediate Carry) by
the symbol H. The 6809's flags are set and reset as described for the hypothetical
microcomputer in An Introduction to Microcomputers: Volume 1.
3-6 6809 Assembly Language Programming
1. Inherent addressing means that the operation code alone tells the processor
what to do. Typical inherent addressing instructions are Halt, No Operation,
and instructions that use specific registers.
2. Register addressing means that only registers are involved in the operation.
Typical of such operations are moving data from one register to another and
exchanging registers.
3. Immediate
4. Base page direct
5. Extended direct
6. Extended indirect
EFFECTIVE ADDRESS
In describing how the processor executes these modes and how the programmer
uses them, we must often refer to the actual address that the processor ultimately
uses to perform the specified operation. We call that address the "effective address":
it is the place from which the processor obtains an operand or in which the processor
stores the result. In some modes (for example, immediate) the effective address is
simply the location immediately following the operation code. In other modes, deter-
mining the effective address may be complicated. The address may be part of the
instruction, the contents of a base register, or the contents of a pair of memory loca-
tions. Determining the effective address may involve computations, such as adding an
offset to a base register. Some of the addressing modes are difficult to understand, since
they involve sequences of operations that finally culminate in an effective address. We
will explain why these sequences are useful and we will describe typical cases from real
applications. You should try to trace each sequence, since the various addressing modes
are the keys to writing programs that are both general and powerful. Remember, the
processor always determines the effective address correctly, no matter how complex the
required operations are.
In the following discussion, we will describe each addressing mode, explain at
least one of its common uses, present a diagram of how it is executed, and discuss a
specific example. All of these together should give you a picture of the power of the
6809 microprocessor.
3-8 6809 Assembly Language Programming
these instructions, the operation codes are complete by themselves; no further address-
ing information is necessary.
REGISTER ADDRESSING
Single-operand instructions can be applied to either Accumulator A or
Accumulator B; the accumulator to be used is specified in the operation mnemonic.
Typical examples are CLRB (Clear Accumulator B) and INCA (Increment Accumula-
tor A). One bit in the actual operation code selects the accumulator. The following
instructions fall in this category: ASL or LSL (Logical Shift Left), ASR (Arithmetic
Shift Right), CLR (Clear: Set to Zero), COM (Ones Complement), DEC (Decrement:
Subtract 1), INC (Increment: Add 1), LSR (Logical Shift Right), NEG (Negate: Twos
Complement), ROL (Rotate Left), ROR (Rotate Right), and TST (Test for Zero or
Minus).
The instructions TFR (Transfer Registers) and EXG (Exchange Registers)
must have two registers of the same size as operands. For example, EXG X,U causes
the processor to exchange the contents of Index Register X and the User Stack Pointer.
The byte following the operation code designates (in coded form) which registers
EXG or TFR is to use. We can illustrate these instructions as follows:
Memory
For details on how the registers are coded, see the descriptions of EXG and TFR
in Chapter 22.
The instructions PSH
(Store Data in Stack) and PUL
(Load Data from Stack)
also require a second byte that designates which registers are to be stored or loaded.
These instructions, however, may load or store any number of user registers. Each bit
of the second byte represents a register; if the bit is set, the processor will store the cor-
responding register in the stack or load it from the stack. details on how the register
For
addressing byte is organized, see the descriptions of the PSH and PUL instructions in
Chapters 11 and 22.
6809 Machine Structure and Assembly Language 3-9
the processor has fetched the operation code. We can illustrate this mode as follows:
Memory
=
Operation Code mmmm
Effective Address
mmmm + 1 Data mmmm + 1
ADDA #$30
Program
XX Memory
•c
X
U
S
PC mm mm
DP
Immediate Addressing
ADDA #$30
One-byte Operand
As a specific example, assume that Accumulator A contains B7 16 initially. After the pro-
cessor executes ADDA #$30, the contents of Accumulator A will be B7 16 + 30 16 =
E7 16 The processor increments its program counter twice, once after fetching the opera-
.
tion code and once after fetching the immediate data, 30 16 in this example.
3-10 6809 Assembly Language Programming
16-Bit Operations
causes the processor to add the 16-bit value 1057 16 to the Double Accumulator D.
Remember, D consists of Accumulators A and B with A holding the high-order byte.
The following diagram shows how the processor executes the instruction.
CCR
Program
XX Memory
•{: VV
U
S
PC mm mm
DP
Immediate Addressing
ADDD #$1057
Two-byte Operand
As a specific example, assume that the initial contents of the Double Accumulator
are 3A48 16 After the processor executes the instruction ADDD #$1057, the contents
.
of the Double Accumulator will be 3A48 16 + 1057 16 = 4A9F 16 The processor incre-
.
ments its program counter three times while executing the instruction, once after fetch-
ing the operation code and once after fetching each byte of the immediate operand.
has a two-byte operation code (10 CE), followed by a 16-bit (two-byte) immediate
operand. We can illustrate the execution of this instruction as follows.
6809 Machine Structure and Assembly Language 3-11
H I N
CCR
Program
Memory
•<:
x
Y
10 mmmm
U
CE mmmm + 1
S
3F mmmm + 2
PC mm mm
2A mmmm + 3
DP
Immediate Addressing
LDS #$3F2A
Two-byte Operation Code
You should refer to Appendix C or to your instruction set summary card if you are
not sure whether an instruction allows immediate addressing.
mmmm
mmmm + 1
Effective Address = pp qq
You should note that 6809 manufacturers usually refer to this mode as "direct,"
whereas Volume 1 of An Introduction to Microcomputers refers to it as "base page."
3-12 6809 Assembly Language Programming
This mode provides a short, quick way to use temporary storage on the direct
page. It is short and quick because the page number is in the direct page register on the
processor chip, thus saving a byte of program memory and a read cycle. Obviously, there
is an overall savings of time and memory only if the programmer rarely changes the con-
tents of the direct page register. Otherwise the instructions that load the direct page
register more than offset the savings from using it.
The standard 6809 assembler uses direct addressing whenever the mode is
available, no other mode is specified, and the address is on the direct page. The as-
sembler assumes that the direct page is page zero (thus maintaining compatibility with
the earlier 6800 microprocessor, which has no direct page register) unless told other-
wise; the programmer may specify a different direct page with a SETDP assembler
directive. The programmer may also force the assembler to use direct addressing by pre-
ceding an address with the symbol "<", but this is rarely necessary.
For example, the assembler converts the statement
ADDA #$30
into an ADD instruction that adds the contents of memory location pp30 16 to
Accumulator A, where pp is the contents of the Direct Page register as shown in the
E F H 1 N z V c
X X X X
1 *l
XX
•<:
X
PC mm mm
DP PP
Direct Addressing
ADDA $30
address 2B30 16 are 6A 16 After the processor executes the instruction, the sum in
.
processor increments its program counter twice, once after fetching the operation code
and once after fetching the direct address.
6809 Machine Structure and Assembly Language 3-13
The direct address occupies only one byte even if the instruction (such as
ADDD, LDS, or STX) handles 16-bit operands. In that case, the processor uses the
addresses ppqq and ppqq + 1 to fetch or store the high-order and low-order bytes of the
data, respectively. Instructions such as LDY and STS require a two-byte operation code,
in which case the base page direct form occupies three bytes of program memory.
follows:
Memory
*
qq mmmm + 2
Effective .._£._-, 4
Address = pp qq
You should note that 6809 manufacturers usually refer to this mode as "extended,"
whereas Volume 1 of An Introduction to Microcomputers refers to it as "direct" or
"extended direct."
This mode allows the processor to access any specific memory location. Of course,
you need not use extended addressing for memory locations that are on the direct page,
mode is shorter and faster. However, extended addressing is
since the base page direct
the usual approach for handling a fixed address that is not on the direct page. This
mode is often used in performing input and output, since the memory addresses
assigned to I/O devices are rarely on the direct page.
The standard 6809 assembler uses extended addressing whenever the mode is
available, no other mode is specified, and the address is not on the direct page. Thus
extended addressing is the general default mode. The programmer may force the assem-
bler to use extended addressing by preceding the address with the symbol ">", but this
is rarely needed.
For example, the assembler converts the statement
ADDA $1C48
into an ADD instruction that adds the contents of memory location 1C48 16 to
Accumulator A as shown in the following diagram.
3-14 6809 Assembly Language Programming
E F H I N z V c
ccrI X X X X
"I
XX
•<:
X
PC mm mm
DP
Extended Addressing
ADDA $1C48
processor increments program counter three times, once after fetching the operation
its
code and once after fetching each byte of the direct address.
If the instruction (for instance, CMPX or SUBD) handles 16-bit operands, the
addresses used are ppqq and ppqq + 1. If the instruction (for example, CMPY) requires
a two-byte operation code, the extended direct form requires four bytes of program
memory.
Effective Address = rr ss
The important point here is to see what this added complication does for us,
besides provide some confusion. Indirection allows a program to use different effec-
tive addresses without being changed, since all the program contains is the location of
the effective address, not its value. Why is that useful? Assume, for example, that our
application involves printing some results, as most applications do. We write a single
routine that takes the results from memory and sends them to an output device. (The
6809 uses memory-mapped input/output, so an output device is addressed using
memory addresses.) However, sometimes those results must be sent to a printer (for
permanent records) while at other times the results are merely displayed (to the opera-
,
tor) or reported via a remote line (to a central computer). If our routine sends the
results using extended indirect addressing, it can send them to any output device. All
the main program must do is place the address of the output device in the specified
memory locations. The approach is the same as that of television commercials which tell
you to call the telephone number that will appear on your screen. The same commercial
can be used nationwide; all the local station does is display the correct local number.
In the standard 6809 assembler format, you specify extended indirect address-
ing by placing the address in square brackets: for example, [D58A]. The address is
always interpreted as a 16-bit value and always occupies two bytes of program
memory. Instructions that use extended indirect addressing require a post byte after
the operation code, and this post byte must contain 9F 16 We will discuss post bytes in
.
into an ADD instruction that adds the contents of memory location rrss to Accumulator
A, where rr is the contents of address D58A 16 and ss is the contents of address D58B 16 .
H I
CCR
A XX
> i
PC mm mm
DP
Indirect Addressing
ADDA [$D58A]
and 35 16 respectively. After the processor executes the instruction ADDA [$D58A], the
sum in Accumulator A will be 1F 16 + ((D58A 16 ):(D58B 16 )) = 1F 16 + (06E4 16 )
= 1F 16 + 35 16 = 54 16 The processor increments its program counter four times, once
.
after fetching the operation code, once after fetching the post byte, and once after fetch-
ing each byte of the indirect address. Clearly this instruction takes extra time to execute
(see Appendix B), since the processor must go through a complex sequence to obtain
the actual data.
mers to handle data structures that are defined by a base address and to write position-
independent code in which the location of the program itself is defined only by a base
address.
3. Where to find the offset if it is necessary. The choices here are: within the
post byte itself, in the next one or two bytes of program memory, in
Accumulator A, in Accumulator B, or in Double Accumulator D.
4. Whether change the base register's contents. The choices here are to add
to
1 or 2 to the base register after using
it (sometimes called "postincrement")
Memory
Post Byte
Offset 1
Offset 2
-Addressing Mode Field
-Indirect Field
(Sign bit when bit 7 = 0)
-Register Field
Figure 3-1. 6809 Post Byte for Indexed and Indirect Addressing
Table 3-4. 6809 Pos By te t Bit A ssignme nts for I ndexed and Indirect Addressing
Bit Number
Addressing Mode
7 6 5 4 3 2 1
R R X X X X X 5-Bit Offset
R R Autoincrement by One
R R I
1 Autoincrement by Two
R R 1 Autodecrement by One
R R 1 1 Auto Decrement by Two
R R 1 Zero Offset
R R 1 1 Accumulator B Offset
R R 1 1 Accumulator A Offset
R R 8-Bit Offset
R R 1 1 6-Bit Offset
R R 1 1 Accumulator D Offset
X X 1 Program Counter 8-Bit Offset
X X 1 1 Program Counter 16-Bit Offset
X X 1 1 1 1 Extended Indirect
il ^
i k i
00 R = X
01 R = Y
10 R = U
11 R = S
6809 Machine Structure and Assembly Language 3-19
register and the offset is to be the distance from the location of the instruction
to the address LABEL. That is, the address LABEL is specified "program
counter relative."
• ,R + means that the 16-bit base register R (X, Y, U, or S) is to be incre-
mented (once for one plus sign, twice for two plus signs) after its contents are
used in determining the effective address.
• ,-R means that the 16-bit base register R (X, Y, U, or S) is to be decre-
mented (once for one minus sign, twice for two minus signs) before its con-
tents are used in determining the effective address.
• Square brackets —11— around an indexed address indicate that it is to be
used indirectly.
Memory
Base Register
mmmm + 2
The offset follows the operation code, which includes the post byte, in program
memory. It is a constant since program memory generally does not change during
program execution. The contents of the base register may vary; the program can deter-
mine the values in the index registers and stack pointers, whereas the program counter
contents depend on the placement of the program.
1
Whefi used with an index register or stack pointer, this addressing mode allows
us to refer to a particular element in an array or list. For example, we may have a set
of ten temperature readings taken at different points in a tank; to change or display a
particular one, we must know where the set of readings starts (base address) and which
we want (index or offset). If, as is usual, we store the readings in successive
reading
memory locations, we can find one by using a constant offset from the base.
Similarly, we may store a record in memory consisting of a person's name,
address, identification number, age, and job classification. If we want to send notices of
change of wage rate to all people in a particular job classification, we can find the job
classification by specifying how far it is from the start of the record (for example, 97
bytes further). This is much like telling all the students who are taking an examination
to put their names on the top line, their class levels on the fifth line, and their dates of
birth on the tenth Each student locates the required lines relative to the top of his
line.
or her form. So, in our records, the name might occupy the first 16 bytes, the address
the next 70, the identification number the next 9, and the age the next 2. We can locate
a particular field in a particular record (for example, employee # 4's identification
number) by specifying the base address (in this case, where employee #4's record
starts) and how far beyond that we must go for the desired field (in our example, 86
bytes to the identification number).
1. The offset is zero. We want to use the base register as an implied memory
address, as described extensively in An Introduction to Microcomputers:
Volume 1.
2. The offset is small enough to fit in the post byte. Since we need one bit to
indicate whether this case holds, and two bits to designate which index
is the base register, the offset must fit in five bits. The
register or stack pointer
6809 microprocessor interprets these five bits (the least significant bits of the
post byte) as a sign (bit 4) and a 4-bit twos complement number (bits
through 3). Thus the range is - 16 10 (10000 2 ) < offset < + 15 10 (01 1 1 2 ).
The advantages of these short modes are obvious: they save time and memory,
sinceno additional bytes are needed for the offset. Furthermore, if the offset is zero, the
processor does not have to go through the motions of adding it to the base.
6809 Machine Structure and Assembly Language 3-21
into an ADD instruction that adds the contents of the address in Index Register to X
Accumulator A. The following diagram illustrates the execution of the instruction.
Data
Memory
CCR
Indexed Addressing
ADDA ,X
Zero Offset
The effective address here is simply the contents of Index Register X. If, for example,
Accumulator A contains B7 16 Index Register X contains 01E1 16 and memory address
, ,
01E1 16 contains 15 16 then after the processor executes ADDA ,X Accumulator A will
,
ments its program counter twice, once after fetching the operation code and once after
fetching the post byte.
Five-Bit Offset
As an example of the short offset mode, the assembler converts the statement
ADDA -1,Y
into an ADD instruction that adds the contents of the address one less than that
specified by Index Register Y Accumulator A. That is, the effective address is the
to
contents of Index Register Y minus 1 The following diagram illustrates the execution of
.
the instruction.
3-22 6809 Assembly Language Programming
E F H 1 N z V c
ccr| X X X X xl
ppqq - 1
4* I xx + yy
XX
•<:
X
_ Program
Y pp qq Memory
U
PC mm mm ~i mmmm + 2 AB mmmm
DP 3F mmmm + 1
mmmm + 2
This mode takes longer for the processor to execute than the zero offset does
because of the address addition. That is, the processor must add the offset (-1 in this
case) to the contents of the base register (Index Register Y). What if the offset is zero?
The processor adds anyway, thus wasting some time. In 6809 assembler notation
it in
the difference is between
ADDA ,X
which tells the processor to use the zero offset mode, and
ADDA 0,X
which tells the processor to use the 5-bit offset mode with a value of zero. Obviously,
you should always use the first notation instead of the second because the first executes
faster: Both are legal, but the second has no advantage. Motorola's 6809 assemblers
automatically optimize to the zero offset mode; thus, a Motorola assembler would
produce the same object code — AB 84 — for both ADDA ,X and ADDA 0,X. Not all
6809 assemblers have this desirable feature, however; you will save yourself poten-
tial trouble by using the special zero offset notation exclusively.
more extra time and memory the instruction requires (see Appendix B). So we use the
longer modes as seldom as possible.
As an example of the 8-bit offset mode, the assembler converts the statement
ADDA $20, U
into an ADD instruction that adds the contents of the address 20 16 beyond the address
in Stack Pointer U to Accumulator A. The 8 -bit offset (20 16 ) is located immediately after
the post byte in program memory. The following diagram illustrates the execution of the
instruction.
Data
Memory
E F H 1 N z V c
CCR X X X X xl
|
iVV ppqq + 20
r
XX
^— _\ xx + yy
D
{:
X
Program
Y Memory
U PP qq
PC mm mm I mmmm + 3 AB mmmm
DP C8 mmmm + 1
20 mmmm + 2
Indexed Addressing
mmmm + 3
ADDA $20. U
One-byte Offset
The effective address here is the contents of Stack Pointer U plus 20 16 . The processor
and the remaining seven bits as a twos complement
interprets bit 7 of the offset as a sign
number. Thus the range of the offset is -128 - 1000 0000 2 < offset < +127 =
0111 1 1 1 2 As a specific example, assume that Accumulator A contains 4D 16 Stack
- ,
Pointer U contains 054E I6 and memory address 056E 16 contains 2A 16 After the pro-
, .
The extension of this mode to a 16-bit offset occupying two bytes is obvious; we
will not discuss it further.
of the program counter. The idea here is the same as a repair manual that first orients
3-24 6809 Assembly Language Programming
the user properly (for example, by telling the person to face the equipment as shown in a
particular picture) and then refers to things as being "in back," "in the top left-hand
corner," or "fourth from the left in the bottom row." These descriptions are all relative
to the user's position.
We can move an entire program along with its data if we refer to addresses relative
to the program counter. The idea here is to refer to data as being "20 locations from
where we are," rather than at a particular address. If we then move everything, the rela-
tive positions of instructions and data remain the same, even though their absolute
addresses change. This is someone that the dining car on a train is two cars
like telling
ahead; the relative positions of the cars remain the same, even though the entire train is
moving.
either an 8-bit or a 16-bit offset from the pro-
The 6809 microprocessor allows
gram counter. No modes are provided, as with the index registers
special zero or 5-bit
and stack pointers. In fact, offsets from the program counter are likely to be large,
since data areas are usually separated from program areas. In the 8-bit offset,
bit 7 is
the sign and bits through 6 are a twos complement number. As an example of this
mode, let us discuss the execution of the instruction
ADDA $10, PC
which adds the contents of the address 13 16 beyond the initial value of the program
counter to Accumulator A. Why is the offset 13 l6 not 10 l6 ? The reason is that the pro- ,
cessor fetches the entire 3-byte instruction (operation code, post byte, and 8-bit offset)
before calculating the effective address. Thus it has already added 3 to the program
counter by the time it uses that register for addressing. In the 16-bit offset mode, the
extra factor is 4 since the instruction occupies four bytes (operation code, post byte, and
16-bit offset). The following diagram illustrates the execution of the instruction ADDA
$10,PC.
E F H I N Z V C Memory
CCR X X X X
A XX
i
PC mm mm
DP
Indexed Addressing
ADDA $10,PC
One-byte offset from Program Counter
The effective address herethe final contents of the program counter plus 10 16 As a
is .
CA + ((PC) + 3 + 10 ) =
16 ,
CA + 16 (7B09 16 + 3 + 10 16 ) = CA + 16
(7B1C 16 ) = CA + 05 - CF The diagram
16 16 16 .
6809 Machine Structure and Assembly Language 3-25
and example show clearly that the result does not depend on where the instruction
this
is program memory, as long as the instruction and the data are moved as a
located in
unit. Here again, the extension to a 16-bit offset is obvious and we will not discuss it
further.
the assembler will figure out the distance from the instruction to address LOCUS
(including the proper factor of three or four) and make that distance into an 8-bit or 16-
bit offset. This is the standard approach to writing position-independent 6809 code
efficiently.
bit used to differentiate between non-indirect and indirect modes — so we must use the
8-bit mode instead. The process of determining the effective address becomes complex
here, since it involves an addition followed by two memory accesses. We can illustrate it
as follows:
Memory
Base Register
mmmm + 1
mmmm + 2
ppqq + rrss
ppqq + rrss + 1
Effective Address = tt uu
The indirection allows us to handle items in arrays, lists, or records which are
addresses rather than data. For example, a microcomputer might be monitoring data
from several remote stations. To each station, we assign a block of memory locations
that contain:
1. Station number
2. Interval between readings
3-26 6809 Assembly Language Programming
Someitems in the block are data, whereas others (#3, #6, #9, and #10) are
addresses. The use of
this block allows the operator to change any of the parameters
without affecting the overall program. The operator can vary the time interval between
readings (item #2), the data area used for temporary storage (item #3), the procedure
for handling invalid readings (item #6), or the output device on which the occasional re-
ports are printed (item #9). We can handle the data with non-indirect indexed address-
ing, whereas we must handle the addresses with indirect indexed addressing. For exam-
ple, if the next reading is in Accumulator A and the address in which that reading is to
be stored (item #3) occupies bytes 4 and 5 of the block, we can store the reading with
the sequence
LDX #BLOCK GET STARTING ADDRESS OF BLOCK
STA [4,X] STORE READING IN MEMORY
If later we want to take that reading (its address is item #3) and send it to the output
device (its address is item #9) , we can use the sequence
LDX #BLOCK GET STARTING ADDRESS OF BLOCK
LDA [4,X] GET MOST RECENT READING
STA [OUT,X] REPORT MOST RECENT READING
Here OUT is the offset for item #9, the address of the output device.
As an example of the indirect indexed mode with constant offset, let us examine
the execution of the instruction
ADDA [5,X]
which adds to Accumulator A the contents of the address stored five bytes beyond the
address in Index Register X. That is, Index Register X is the base; the instruction adds 5
(the offset) to the base and uses the sum as an indirect address. This mode obviously
requires extra execution time (see Appendix B) because of the addition and the subse-
quent memory accesses. The following diagram illustrates the execution of the instruc-
tion.
6809 Machine Structure and Assembly Language 3-27
E F H 1 N z V c
CCR 1 X X X X
*l
XX
{:
X
I
Program
Y Memory
U
PC mm mm _^ ^ mmmm + 3 J AB mmmm
DP 98 mmmm + 1
05 mmmm + 2
0C39, 6 contains D2 16 and memory address A0D2 16 contains 47 16 After the processor
, .
The processor executes all these similarly to the 8-bit offset mode described ear-
lier. Note that there is no special zero offset mode using the program counter. We can
use the PCR (program counter relative) notation to simplify the specification of rela-
tive addresses as we discussed previously.
3-28 6809 Assembly Language Programming
Memory
Base Register
A common use of this mode is to access lookup tables. Let us assume, for exam-
ple, that we have a lookup table in memory that converts 8-bitASCII character codes to
8-bit EBCDIC character codes. The table consists of EBCDIC codes, organized accord-
ing to the ASCII codes
which they correspond. For instance, the 0th entry is the
to
EBCDIC code corresponding to the ASCII code 0, the 15th entry is the EBCDIC code
corresponding to the ASCII code 15 (0F 16 ), and the 43rd entry is the EBCDIC code cor-
responding to the ASCII code 43 (2B 16 ). To convert an ASCII code to EBCDIC, we
need to know where the table starts (let's call it address EBCDIC) and the value of the
ASCII code (let's assume it is stored temporarily in address CHAR). Then we can use
the accumulator offset mode to fetch the EBCDIC code from the table. A typical pro-
gram is:
For more details on character codes, see Chapter 6 of this book and Chapter 3 of
Volume 1 of An Introduction to Microcomputers. For further discussions of lookup tables,
which loads Accumulator A from the address obtained by adding Accumulator B and
Index Register X. The mode using Accumulator A for the offset clearly works the same
way; the double accumulator offset mode is similar except for the offset's length. Note,
however, that the processor interprets the contents of a single accumulator as an 8-bit
—
signed twos complement number. Thus the accumulator offset mode has a slightly
different effect than the ABX instruction, which interprets the contents of
Accumulator B as an 8-bit unsigned number. Accumulator offset addressing requires
extra time because the processor must add the offset and the base; it does not require
any extra memory since the offset is in an accumulator or double accumulator. The
double accumulator version is necessary when the table occupies more than 256 bytes.
The following diagram illustrates the execution of the LDA B,X instruction.
Data
Memory
E F H 1 N Z V c
CCR
c X X
I
~ XX ppqq + yy
"^
°{: yy
X
JV J
pp qq
Program
Y
Memory
U
PC mm mm i. mmmm + 2 J A6 mmmm
DP 85 mmmm + 1
mmmm + 2
changing the table. For example, the operator could let device #6 be a CRT display for
a test run (thus showing test results without wasting paper) a printer for a run with local
,
output (thus providing a permanent record) and a modem for a run that must be re-
,
ported to central headquarters (thus sending the data over a communications link)
The procedure for reading data from a numbered input device is:
1. Load the starting address of the device table into an index register or stack
pointer.
For example, if the starting address is IOTBL and the device number (assumed to
be even) is in memory address IODEV, a typical program is:
LDX #IOTBL GET BASE ADDRESS OF DEVICE TABLE
LDB IODEV GET I/O DEVICE NUMBER
LDA [B,X1 GET DATA FROM I/O DEVICE VIA TABLE
Remember, the elements in the table are 2-byte addresses and we want to transfer
data to or from those addresses, not to or from the table itself. The entries in the table
tell us where to send data or obtain data, not the value of the data as in the code con-
version example shown in the non-indirect case. Here again, the offset is a variable,
since the same program must be able to convert various device numbers into actual I/O
addresses.
As an example of the indirect accumulator offset mode, we will discuss the
instruction
LDA [B.X1
which loads Accumulator A from the address starting at the address obtained by adding
Accumulator B and Index Register X. The next diagram illustrates the execution of the
instruction. The Accumulator A and double accumulator offsets are handled similarly,
so we will not describe them in detail. The double accumulator offset is used for tables
that exceed 256 bytes in length, a relatively infrequent situation. Clearly this mode
takes extra time (see Appendix B) because of the indirection. The processor must
calculate where the indirect address is and fetch the indirect address from memory
before it can actually execute the instruction. As with the non-indirect version, no
additional program memory is necessary since the offset is in an accumulator or double
accumulator.
2 2
E F H 1 N z V c
ccrI X X
1
ppqq + yy
ppqq + yy + 1
As a specific example, let us assume that Index Register X contains 03C6 16 (the
starting address of the I/O device table), Accumulator B contains 04 (device #4), and
memory addresses 03CA 16 and 03CB 16 (which hold the address corresponding to device
#4) contain 80 16 and 12 16 respectively. Let us further assume that the data currently at
address 801 16 (the input device port) is 43 16 (an ASCII C). Then after the processor
executes the instruction LDA [B,X] Accumulator A will contain
(((X) + (B)):((X) + (B) + 1)) = ((03C6
04 16 ):(03C6, 6 + 05 16 )) -
16 +
((03CA 16 ):(03CB 16 )) ) = (8012 16 = 43 16 (ASCII C,
the data from the input port). The
idea here is to use the table to determine where to find the data. The end result is that
Accumulator A contains the data read from input device #4, which is accessed through
memory address 801 16 , the corresponding entry in the device table.
averaging a set of ten readings, we must add them together one by one (for instance,
start with zero,add the first reading, add the second reading, add the third reading, etc.)
and finally divide by 10.
Thus to handle one byte and move forward, we must:
• Reach the byte using the address in an index register or stack pointer.
• Add 1 to the index register or stack pointer to make it point to the next byte.
The effect is like the action of a typewriter, which both prints the character for the key
you press and moves the carriage along to the next position. Subtracting 1 from the
index register or stack pointer would correspond to backspacing the typewriter's car-
riage. Unlike the typewriter, the computer does not prefer forward over backwards.
Autoincrementing and autodecrementing are the modes most like the indexed address-
ing described in Volume 1 of An Introduction to Microcomputers.
The 6809 offers different step sizes for autoincrementing and autodecrement-
ing. The base address may be:
• Incremented by 1 after it is used.
• Incremented by 2 after it is used.
• Decremented by 1 before it is used.
• Decremented by 2 before it is used.
The increment or decrement by 2 approach is useful when the array consists of 16-bit
data or addresses. The processor thus moves on to the next element automatically,
even though that element is located two bytes away from the current element. Applying
the increment after using the base but applying the decrement before using the base
maintains compatibility with the automatic use of the stack pointers (in JSR, PSH,
PUL, RTI, RTS, and SWI instructions and in interrupt responses). Any access/change-
pointer sequence could be implemented, but this is the most popular approach. All the
user must remember is to load the base register with the starting address of the array or
string for autoincrementing, but with the ending address plus 1 or 2 for autodecrement-
ing (because the autodecrement will reduce the base register before using it)
first
summation or averaging program. The following diagram shows how the processor
executes the instruction.
6809 Machine Structure and Assembly Language 3-33
E F h I N z v c
CCR
XX
<:
X pp qq
Program
Y Memory
U
PC mm mm AB mmmm
DP 80 mmmm + 1
mmmm + 2
X contains 07E4 16 and memory location 07E4 16 contains 05 16 Then, after the processor
, .
Thus the instruction both adds an element to Accumulator A and updates Index
Register X so it points to the next element.
This instruction adds to the double accumulator the contents of the address obtained by
subtracting 2 from Index Register Y. It also places the result of the subtraction back in
Index Register Y. Here the elements are 16 bits long, so a subtraction of 2 is necessary
to reach the next element in the array. The step of 2 takes a little extra time (see Appen-
dix B). The processor, of course, has no preference between autoincrementing and
autodecrementing, since it lacks human or cultural preferences such as positive over
negative, forward over backwards, left-to-right over right-to-left, or top-to-bottom over
bottom-to-top. The following diagram illustrates the execution of the instruction.
Y
E F H 1 N z V c
ccrI X X X xl
XX
D {*.
yv
Y PP qq
PC mm mm
DP
Indexed Addressing
ADDD , —
Autodecrement by Two
As a specific example, let us assume that the double accumulator contains 10E8 16 Index ,
Register Y contains 042D 16 and memory locations 042B 16 and 042C 16 contain 09 16 and
,
= 042B 16 Thus the instruction first updates Index Register Y and then adds the current
.
and thus test the system, use the system as a remote terminal, or choose temporary or
hard-copy output without making any changes in the underlying program. Let us
assume that we want to fetch data from one device after another or test input devices
until we find one that has new data available. We can fetch data from the first input
device in a table INDEV with the sequence of instructions.
LDU # INDEV GET BASE ADDRESS OF INPUT DEVICE TABLE
LDA [»U++] GET DATA FROM DEVICE #0
After the processor executes these instructions, Accumulator A contains the data from
device #0 and Stack Pointer U points to the address corresponding to device #2. Thus
we can continue through the table of I/O devices, incrementing the pointer by 2 after
6809 Machine Structure and Assembly Language 3-35
fetching data from a particular device. Obviously, we could equally well start two beyond
the end of the table and use autodecrementing by 2 to move through the table back-
wards.
Since an address always occupies two bytes of memory, incrementing or decre-
menting by 1 makes no sense; it would result in the processor picking up half of one
address and half of another. This mode is therefore not allowed with indirection, and the
assembler will give you an error message if you try to use it. The only valid options are:
CCR
the instruction loads Accumulator A from an indirect address obtained from the table
and updates Stack Pointer U so it points to the next indirect address. Of course, this pro-
cess of picking up an indirect address from the table, loading the data from that
address, and updating the pointer takes many extra clock cycles (see Appendix B).
Note, however, that no extra bytes of program memory are needed, since no offset is
involved.
Updated contents
Program Counter = ppqq Operation Code 1
of
> Operation Code: One or two bytes long
Operation Code 2
The 6809 microprocessor has two forms of relative addressing: 8-bit offset and 16-bit
offset. Inboth forms, the value following the operation code specifies how many
memory locations to skip over from the end of the instruction. The offset is a twos com-
plement number, so the range for the 8-bit form is
-128 (= 1000 0000 2 or 80 16)< offset < +127 (=0111 llll 2 or7F 16)
6809 Machine Structure and Assembly Language 3-37
Since the short relative branches themselves occupy two bytes of program
memory, the range from the start of the instruction is
the assembler will figure how far away label CHCNT is (including the factor of 2) and
place that number in the offset. We will discuss calculating relative offsets in more detail
in Chapter 4.
As an example of how the processor executes relative branch instructions, con-
sider the instruction
BRA PLACE
where PLACE is a nearby address. If the program counter contains mmmm originally,
the offset is the 8-bit twos complement form of PLACE — (mmmm + 2) = PLACE —
mmmm — 2. The next diagram illustrates the execution of the instruction. The 16-bit
offsetform is similar, except that the offset occupies two bytes and the instructions
therefore occupy either three bytes (LBRA and LBSR) or four bytes (all long condi-
tional branches). The extra factor in the address calculation is then either 3 or 4, making
hand even more awkward. As we mentioned above, the assembler will
calculations
perforin the calculation for you if you specify the destination address as a label; you
will seldom need to calculate offsets by hand. The 16-bit offset provides access to any
location in memory, but is not commonly needed since few branches are long enough to
require its use. Another approach to providing relative addressing with branches is to
use the Jump or Jump-to-Subroutine instructions with the indexed addressing mode
that involves an offset from the program counter. The non-indirect versions of these
instructions, however, take more time and memory than ordinary relative branches
and so are not used.
CCR
A Program
i Memory
x mmmm
Y mmmm + 1
U mmmm + 2
S
PC mm mm
DP mmmm + 2
+ offset
the instruction BRA PLACE, the contents of the program counter will be (initial PC) +
2 + offset - C5A1 16 + 2 + 1B 16 - C5A3 16 + 1B 16 = C5BE 16 = PLACE. Note that if
we move the entire program forward or backwards by a distance REL, the new offset is
(C5BE 16 + REL) - (C5A1 16 + REL) - 2 = C5BE 16 - C5A1, 6 - 2, the same as
before since the RELs cancel out.
6800/6809 COMPATIBILITY
The 6809 microprocessor is an advanced version of the 6800 microprocessor,
produced by the same manufacturers. All assembly language programs written for
the 6800 microprocessor can also be assembled for the 6809 microprocessor. In fact,
object code produced for the 6800 microprocessor is very similar to that produced for
the 6809 microprocessor; in many cases, the processors have direct object code com-
patibility. The external support devices designed for use with the 6800 microprocessor
can all be used with the 6809 as well. Chapter 9 of An Introduction to Microcomputers:
Volume 2 discusses the hardware compatibility in more detail.
6809 Machine Structure and Assembly Language 3-39
Notes:
1. Shading identifies additions or modifications to the 6800 instruction set The unshade d instruc-
tions are also6800 instructions with the same operation codes except bs noted below.
2. R1 and R2 may be any pair of 8-bit or 1 6-bit registers. The 8-bit register s are A, B, CC:. and DP.
The 1 6-bit registers are D, X, Y, U. S, and PC.
5. This instruction does not affect the Carry flag. On the 6800/6801/6802 it clears the C flag.
6. These do not affect the Overflow flag (V). On the 6800/6801/6802 they may.
7. This instruction correctly sets all flags. On the 6800/6802 it does not.
8. On the 6809, the Entire flag (E) is checked during RTI to determine how mu ch to unstack — the
entire register complement or just the Condition Code Register and Return A ddress.
9. SWI sets the F and I flags; SWI2 and SWI3 have no effect on F and I.
10. These instructions are implemented on the 6800 with slightly different mnemonics.
11. This instruction is implemented on the 6800 as PSH.
12. This instruction is implemented on 6800 as PUL.
3-40 6809 Assembly Language Programming
We will briefly describe and compare the 6809 and 6800 microprocessors with
regard to their registers, flags, addressing modes, and instruction sets. The processors
are similar, and the manufacturers clearly will encourage migration from the 6800 to the
6809. This description will help you see what problems you would encounter in going
from one CPU to the other.
REGISTERS
The 6800register set is a subset of the 6809 register set. In addition to the 6800
registers —
Condition Code, Accumulators A and B, Index Register X, and the Hard-
ware Stack Pointer — the 6809 has another index register (Y), another stack pointer
(User Stack Pointer or U register), and a direct page register. Also, the 6809 allows
references to the Double Accumulator D, which consists of Accumulator A and
Accumulator B, whereas the 6800 does not.
FLAGS
The 6800 and 6809 microprocessors have identical Sign, Zero, Overflow, Carry,
Half (or Auxiliary) Carry, and Interrupt Mask flags. The 6809 also has a Fast Inter-
rupt Mask and an Entire flag (E) which are not implemented on the 6800,
flag (F)
since the 6800 has no Fast Interrupt Request input and always saves all of its registers in
response to an interrupt. Bit positions 6 and 7 in the 6800's condition code register
always contain ones.
ADDRESSING MODES
The 6809 microprocessor has many more addressing modes than does the 6800.
The only indexed addressing mode that is implemented on the 6800 is the non-
indirect mode with an 8-bit unsigned offset from Index Register X. All other indexed
and indirect addressing modes are unique to the 6809. You should note that 6809
indexed instructions all require an extra (or post) byte that determines the addressing
mode. Thus an indexed instruction that required two bytes of code on a 6800
microprocessor will generally require three bytes on a 6809 microprocessor. However,
indexed addressing on the 6800 is most often used with an offset that is either zero or
less than 16; instructions with such small offsets can be implemented on the 6809
microprocessor using the special forms for zero offset or 5-bit signed offset, thus making
them again two bytes in length. You should also note that indexed offsets are signed in
the 6809 microprocessor (allowing them to be either positive or negative) whereas they
,
INSTRUCTIONS
The 6800 instruction set is a subset of the 6809 instruction set. Many 6800 and
6809 instructions are identical (see Table 3-6). Some new 6809 instructions (see Table
3-7) are obvious additions to the 6800 set, required to handle the new 6809 registers.
Still other 6809 instructions are generalizations of 6800 instructions (see Table 3-8) or
6800/6809 DIFFERENCES
You should note the following minor differences between the 6800 and 6809
instruction sets:
6800 instructions that use the stack pointer always decrement it after storing
data and increment it before loading data. Thus the hardware stack pointer on
the 6809 should be initialized to a value one larger than that used in a com-
parable 6800 program.
3. The 6800 instructions TSX (Transfer Stack Pointer to Index Register) and
TXS (Transfer Index Register to Stack Pointer) took account of the fact
that the 6800's stack pointer contained the address one beyond the end of the
stack. This accounting involved an addition of 1 during TSX and a subtrac-
tion of 1 duringTXS, thus moving to or from the last occupied address. The
6809 microprocessor does not require this awkward adjustment and
therefore does not implement it in instructions.
4. The 6809 TST instruction does not affect the Carry flag, whereas the 6800
TST instruction clears that flag.
5. The 6809 right shifts (ASR, LSR, ROR) do not affect the Overflow flag,
whereas the 6800 right shifts do.
ADCA/ADCB ADCA/ADCB
ADDA/ADDB ADDA/ADDB
ANDA/ANDB ANDA/ANDB
ASL ASL (also LSD 1
ASR ASR 1
CM PA/CM PB CM PA/CM PB
COM COM 1
CPX CMPX 3
DAA DAA
DEC DEC 1
EOR EOR
INC INC 1
JMP JMP 1
JSR JSR
LDAA/LDAB LDA/LDB
LDS LDS 2
LDX LDX 2
LSR LSR 1, 3
NEG NEG 1
NOP NOP 2
ORAA/ORAB ORA/ORB
PSH PSHS 2, 4
PUL PULS 2, 4
ROL ROL 1
ROR ROR 1, 3
RTI RTI
RTS RTS
SBC SBC
STAA/STAB STA/STAB
STS STS 2
STX STX 2
SUBA/SUBB SUBA/SUBB
SWI SWI
TST TST 1, 3
Note the minor differences in some of the mnemonics — namely, an extra A in LDAA, LDAB, ORAA,
ORAB, STAA, and STAB on the 6800, an extra S in PSHS and PULS on the 6809, and a slightly
different version of Compare Index Register X (CMPX on 6809, CPX on 6800).
Notes:
1. Direct addressing is available with this instruction on the 6809 only.
7. The 6809 sets all flags properly after executing CMPX and similar instruc-
tions, whereas the 6800 sets only the Z flag properly after executing its CPX
instruction.
Clearly these differences will not affect most programs, unless they perform many
stack manipulations. There are slight differences in operations involving the Condition
Code register, since the 6800 always has ones in the two most significant bits of that
register, whereas the 6809 uses those bits for the Entire flag and the Fast Interrupt Mask
bit.
CMPY CPX
LDU LDS
LDY LDX
PSHU PSH
PULU PUL
STU STS
STY STX
Instruction Mnemonic
6801/6809 COMPATIBILITY
The 6801 microprocessor is a slightly improved version of the 6800
microprocessor that is manufactured by some of the same companies. The 6801
instruction set is almost the same as the 6800's except that the 6801 has a multiplication
instruction and a ABX instruction (as on the 6809), as well as 16-bit shifts for the dou-
ble accumulator that are not implemented on either the 6800 or the 6809. The 6801,
like
the 6809, does set the flags properly after CMPX (CPX). The only added difference is
that the 6801 multiply instruction (MUL) does not affect the Zero flag, whereas the
6809 MUL instruction does.
6809 Machine Structure and Assembly Language 3-45
6502/6809 COMPATIBILITY
The 6809 microprocessor is also similar to the 6502 and related
microprocessors, which are produced by a different group of manufacturers. For more
details on 6502 compatibility, see the discussions in Chapters 9 and 10 of An Introduction
to Microcomputers: Volume 2 and in Chapter 3 of 6502 Assembly Language Programming. 3
1. A space after a label. All labels must start in column 1 and all statements that
are not labeled must start with at least one space.
2. A space after the operation code. The accumulator, double accumulator, or
index register/stack pointer designation can be added to the operation code
without a space; for instance, ADDA
for "Add to Accumulator A," STD for
"Store Double Accumulator," and PSHU for "Push Registers onto User
Stack."
3. A comma between operands in the address field — that is, between an offset
value or register and a base register (X, Y, U, S, or PC). For example, ADDA
$35,X means that an indexed instruction is to be generated with an offset of
35 16 from the value in Index Register X. A zero offset can be omitted unless
the base register is the program counter.
4. A comma in front of the symbols for autoincrementing or autodecrement-
ing. For example, LDA ,X + tells the assembler to generate an indexed LDA
instruction which autoincrements Index Register X by 1. Similarly, ADDB
, U tells the assembler to generate an indexed ADDB instruction which
autodecrements Stack Pointer U by 2. This comma is similar to the one be-
tween operands (item 3 above) although no offset is allowed with autoincre-
,
menting or autodecrementing.
5. Square brackets —II — around addresses to be used indirectly.
6. A space before a comment that appears on the same line as an instruction,
and an asterisk before an entire line of comments.
Typical 6809 assembly language instructions are:
LABELS
Most versions of the assembler allow only six characters in labels and truncate
The first character must be a letter or the special character period (.).
longer labels.
The assembler reserves certain names to refer to CPU registers; these names are A,
B, CC, D, DP, PC, PCR (program counter relative), S, U, X, and Y. The use of opera-
tion mnemonics as labels is often not allowed and is not good programming practice
anyway, because of the obvious confusion.
ASSEMBLER DIRECTIVES
The assembler has the following explicit pseudo-operations:
Examples:
ADDR FDB $3165
places the numbers 31 16 and 65 16 in thenext two bytes of program memory and assigns
the name ADDR to the address of the first byte; thus (ADDR) = 31 16 and (ADDR +
1) -65 16.
TCONV FCB 3 2
places the number 32 (20 16 ) in the next byte of program memory and assigns the name
TCONV to the address of that byte.
ERROR FCC /ERROR/
We will always use the first form shown (with the / character) for consistency.
places the addresses FADD, FSUB, FMUL, and FDIV in the next eight bytes of
memory and assigns the name OPERS to the address of the first byte. All addresses (and
16-bit data items) are stored with their high-order bits first.
RMB
RMB is the Reserve directive used to assign locations in memory for specific pur-
poses; it allocates a specified number of bytes.
EQU
EQU is the Equate or Define directive used to define names.
ORG
ORG is the standard Origin directive. 6809 assembly language programs usually
have several origins, which are used for the following purposes:
Examples:
RESET EQU $3800
ORG RESET
ORG $FFFE
FDB RESET
Note: $ means 'hexadecimal'.
This sequence places the Reset (or startup) instruction sequence in memory beginning
at address 3800 16 , and places that address in the memory locations (addresses FFFE
16
and FFFF 16 ) from which the 6809 CPU retrieves the Reset address.
MAIN EQU SC000
ORG MAIN
This sequence specifies that the instructions following it are to be placed in memory
beginning at address C000 16 .
3-48 6809 Assembly Language Programming
END
END simply marks the end of the assembly language program.
SETDP
SETDP specifies which page of memory is to be treated as the direct page for
subsequent assembly. After a SETDP directive, the assembler will generate instruc-
tions using the direct addressing mode whenever an address is located on the specified
page. If the programmer does not specify a direct page with a SETDP directive, the direct
page is assumed to be page (the high-order byte of every address is zero) for 6800
compatibility. Note that SETDP does not generate the object code required to load the
Direct Page register; the programmer must place the required instructions (such as
LDA #DPAGE; TFR A,DP) in the source program.
1 Simple equates, such as MAIN EQU $C000, require labels since their purpose
is to define the meaning of those labels.
ADDRESSES
The Motorola 6809 Assembler allows entries in the address field in any of the
following forms:
Example: 1247
Note that you must place a zero in front of hexadecimal numbers that begin
with a letter (A through F), so that the assembler can distinguish them from
"$"
names, if you are using the format with a terminating H. We will use the
symbol to maintain compatibility with the 6800 assembler.
We will use the "@" format to maintain compatibility with the 6800 assem-
bler.
6809 Machine Structure and Assembly Language 3-49
Example: •
h
Example: *+i
The assembler will generate an indexed LDA instruction using the mode
based on a constant offset from the program counter. The value of the offset
will be the relative distance between TABLE and the current value of the
location counter. Note the difference between LDA TABLE,PCR and LDA
TABLE,PC: the latter generates an indexed LDA instruction with TABLE as
the value of the offset to be added to the program counter. The assembler au-
tomatically calculates the relative distance to the destination when the pro-
grammer uses the PCR notation.
1. Direct and Extended are the default modes. The assembler chooses direct
addressing if the address is on the page specified as the direct page. Remem-
ber that the direct page is page unless a SETDP directive specifies otherwise.
You can force the asssembler to use direct addressing by preceding the
address with the "< " character and to use extended addressing by preceding
the address with the ">" character.
2. The symbol # precedes the data for immediate mode.
3. OFFSET,R specifies indexed non-indirect modes with offsets. R must be
one of the PC, S, U, X, or Y. You can force an 8-bit offset mode by
registers
preceding the operand with the "<" character and a 16-bit offset mode by
preceding the operand with the ">" character. The assembler will automat-
ically choose the zero offset, 5-bit offset, or 8-bit offset mode if the mode is
All intermediate results are truncated to 16-bit integers and all fractional
tions.
REFERENCES
Terry Ritter and Joel Boney, the co-architects of the Motorola 6809, have de-
scribed its architecture and instruction set in a series of three very interesting articles
entitled "AMicroprocessor for the Revolution: The 6809" in BYTE magazine. These
articles describe the philosophy that resulted in the 6809 microprocessor and answer
many questions about approaches to problems, design decisions, and tradeoffs. The
specific articles in the series are:
and J. Boney, "A Microprocessor for the Revolution: The 6809. Part
T. Ritter 1:
T. Ritter and J. Boney, "A Microprocessor for the Revolution: The 6809. Part 3:
Explanatory notes that discuss the instructions and methods used in the pro-
gram
You should use the examples as guides for solving the problems at the end of each
chapter.Be sure to run your solutions on a 6809-based microcomputer to ensure that
they work correctly.
Program Listing Format
We reproduce Program 4-1 below to illustrate the format for program listings
which we will use in this hook. This is a common format for assembler output; it
shows the object code as well as the source code.
Memory Object
Address Code Source Program
The 4-digit number starting in the leftmost column of each line is the hexadecimal
address of the first byte of object code generated from the line of source code. For
example, in the second line 0002 is the address of the object code byte for STA (base
page direct addressing form). The digits following the address are the hexadecimal
is the object code for STA
object code for the instruction. Thus, in the second line, 97 41
$41, and the byte 97 is in location 0002. The byte 41 is in location 0003; we infer this
from the fact that it The letters, numbers, and words
follows the byte in address 0002.
to the right of the object code are the assembly language fields which we described in
Chapter 2. These fields comprise the source program.
If you wish to assemble these examples on your microcomputer, key in the
source statements only; do not enter the addresses or object codes, since the assembler
program will generate them. You will also need to enter some assembler directives —
for example, to tell the assembler where to start program addresses. We may not show
all the necessary directives; the ones you use will be determined by your assembler and
1. Comment each program so that others can understand it. The comments
may be brief and ungrammatical; they should explain the purpose of an
instruction or a section of the program. Comments should not describe the
operation of instructions; that description is available in manuals. You do not
have to comment each statement or explain the obvious. You may follow the
format of the examples but provide less detail.
6. Use hexadecimal notation for addresses. Use the clearest possible form for
data.
7. If your microcomputer allows it, start all programs in memory address
0000 and use memory addresses starting with 0040 16 for data and tempor-
ary storage. Otherwise, establish equivalent addresses for your microcom-
puter and use them consistently. Again, consult your user's manual.
8. Use meaningful names for labels and variables — for example, SUM or
CHECK rather than X, Y, or Z.
9. Execute each program on your microcomputer. This is ultimately the only
way to verify that the program functions correctly. We have provided sample
data with each problem, but be sure that the program works for all special
cases.
Accumulator Operations
Almost all processing instructions (for example, Add, Subtract, AND, OR) use
the contents of an accumulator as one operand and place the result back in the same
accumulator. In most cases, you will load the initial data into an accumulator with LDA
or LDB. You will then store the result (from the same accumulator) with STA or STB.
Memory Operations
Some instructions — shifts, clear, increment (add 1), decrement (subtract 1),
and ones or twos complement — can act directly on data in memory. Such instructions
allow you to bypass the user registers, but each executes more slowly than the equiva-
lent instruction that acts on a register. A memory operation is slower because the CPU
must load the data into a temporary register, perform the operation, and then store the
result back into memory. Therefore a sequence of operations on one memory location
will execute more slowly than the sequence which operates on the same data in a
register, even though the latter sequence must be two instructions (a load register and a
store back to memory) longer. Of course, for a single operation the one instruction that
operates directly on memory executes faster than the three instructions (load, operate,
store) required to obtain the same result through a register operation. Thus, operating
directly on memory is slower than register operation unless the register load and
store overhead eliminates the time savings resulting from register use.
4
Beginning Programs
This chapter contains some very elementary programs. They will introduce
some fundamental features of the 6809. In addition, these programs demonstrate some
primitive tasks that are common to assembly language programs for many different
applications.
PROGRAM EXAMPLES
4-1. 8-BIT DATA TRANSFER
Purpose: Move the contents of memory location 0040 to memory location 0041.
Sample Problem:
(0040) = 6A
Result: (0041) = 6A
Program 4-1:
0000 96 40 LDA $40 GET DATA
0002 97 41 STA $41 TRANSFER TO NEW LOCATION
0004 3F SWI
we can
with zeros in their eight most significant bits are on the direct page. Therefore,
use the direct (or base page) forms of LD A and ST A in which the instructions need only
specify the eight least significant bits of the memory address in the byte following the
operation code. Wecan omit the leading zeros just as we do in everyday conversation
(e.g., we say "sixty cents" rather than "zero dollars and sixty cents"). However,
remember that the addresses are really 0040 16 and 0041 16 .
Before you execute the example program, you will have to load the data into
memory location 0040 16 After you execute the program, you can see the result in
.
Sample Problem:
(0040) = 38
(0041) = 2B
Result: (0042) = 63
Program 4-2:
0000 96 40 LDA $40 GET FIRST OPERAND
0002 9B 41 ADDA $41 ADD SECOND OPERAND
0004 97 42 STA $42 STORE RESULT
0006 3F SWI
This program uses the direct (base page) forms of LDA, ADDA, and STA, since
we have placed all the addresses on the direct page. We use direct page addressing
will
throughout this book, in order to make the example programs shorter and thus easier to
key into memory by hand.
ADDA affects the Carry flag, but LDA and STA do not. Only arithmetic and shift
instructions affect the Carry; logical and transfer instructions do not.
LDA and ADDA do not affect the contents of memory, but they do affect the
contents of Accumulator A. On the other hand, STA changes the contents of the
addressed memory location, but does not affect the contents of Accumulator A.
Before you execute this example program, you will have to load the two operands
into memory locations 0040 and 0041 16 After you execute the program, you can see
16
.
program would store the data in memory and a subsequent section would use the result.
Sample Problem:
(0040) « 6F = 0110 1111 2
Program 4-3:
0000 D6 40 LDB $40 GET DATA
0002 58 ASLB SHIFT LEFT
0003 D7 41 STB $41 STORE RESULT
0005 3F SWI
Unlike the two previous programs, this one uses Accumulator B. There is no com-
we could use Accumulator A in this program, and
pelling reason for these preferences;
we could use Accumulator B in either of the previous programs. Accumulators A and B
are virtually interchangeable; most instructions can use either one. We will note a few
differences in later chapters.
ASLB shifts Accumulator B left one bit and clears the least significant bit position
(bit 0). The previous contents of bit position 7 go into the Carry flag. The result (includ-
ing the Carry flag) is twice the original data (why?).
We shift the contents of memory location 0040 left one bit with the
could also
instruction ASL$40 and then move the result to memory location 0041. However, this
method would change the contents of memory location 0040 as well as the contents of
memory location 0041. How would you change the program to operate on a memory
location without changing the contents of location 0040?
Compare the bit patterns for instructions that use Accumulator A with those that
use Accumulator B. How do the bit patterns differ? How does the processor know
1
Sample Problem:
(0040) = 3D = 0011 11 01 2
Program 4-4:
0000 96 40 LDA $40 GET DATA
0002 84 OF ANDA #%00001111 MASK OUT FOUR MSB'S
0004 97 41 STA $41 STORE RESULT
0006 3F SWI
A logical AND instruction may be used to clear bits that are not meaningful.
For example, the four least significant bits of the data could be an input from a ten-posi-
tion switch or an output to a numeric display. Remember that logically ANDing a bit
with '0' always produces a zero result, while logically ANDing a bit with '1' does not
change its value.
Program 4-5:
0000 OF 40 CLR $40 CLEAR MEMORY LOCATION 0040
0002 3F SWI
The CLR instruction can act directly on a memory location, without the need for a
user register. Of course, the processor does not really clear the memory location
directly; instead, generates a zero internally (using a register that the programmer can-
it
Sample Problem:
(0040) » 3F
Result: (0041) s 03
(0042) = OF
Program 4-6:
0000 96 40 LDA $40 GET DATA
0002 84 OF ANDA noooomi MASK OFF MSB'S
0004 97 42 STA $42 STORE LSB'S
0006 96 40 LDA $40 RELOAD DATA
0008 44 LSRA SHIFT MSB'S TO LEAST
0009 44 LSRA SIGNIFICANT POSITIONS
0O0A 44 LSRA AND CLEAR OTHER
OO0B 44 LSRA POSITIONS
O00C 97 41 STA $41 STORE MSB'S
000E 3F SWI
Each execution of LSR shifts an accumulator or memory location right one posi-
tion, so four LSRs are required to shift four positions. LSR always clears the most sig-
nificant bit of the result (a so-called "logical shift"), so four LSRAs clear the four most
significant bits ofAccumulator A.
Rewrite the program so that it saves a copy of the data in Accumulator B rather
than loading it twice. Use the instruction TFR A,B. This instruction moves the contents
of A to B without changing A. Which version do you prefer, and why?
Beginning Programs 4-5
Sample Problems:
a. (0040) 3F
(0041) m 2B
Result: (0042) = 3F
b. (0040) - 75
(0041) A8
Result: (0042) = A8
Program 4-7:
0000 96 4 LDA $40 GET FIRST OPERAND
0002 91 41 CMPA $41 IS SECOND OPERAND LARGER?
0004 24 02 BHS STRES
0006 96 41 LDA $41 YES, GET SECOND OPERAND
0008 97 42 STRES STA $42 STORE LARGER OPERAND
000A 3F SWI
CMPA $41 subtracts the contents of memory location 0041 from the contents of
Accumulator A, but does not save the result anywhere. All the CMPA instruction does
is setthe flags for branching; it leaves the value in Accumulator A unchanged, so that
value can be used for later comparisons or other operations.
CMPA affects the flags as follows:
1. The Carry flag (C) is set to 1 if the unsigned subtraction requires a borrow and
to if it does not.
2. The Zero flag (Z) is set to 1 if the result of the subtraction is zero and to if it
is not.
3. The Sign flag (N) takes the value of the most significant bit of the result of the
subtraction.
4. The Overflow flag (V) is set to 1 if the subtraction causes twos complement
overflow and to if it does not.
The following cases are particularly important since they are often used for
branching:
1. Z= 1 if the operands are equal; Z= if the operands are not equal. Thus you
can use BEQ or BNE after a CMP instruction to check for equality.
2. C = 1 if the contents of the memory location are larger (in the unsigned
sense) than the contents of the accumulator; C = if the contents of the
memory location are smaller than or equal to the contents of the accumulator.
Remember that CMPA calculates (A) — (M), where M is the selected
memory location. A borrow is necessary if (M) is larger.
4-6 6809 Assembly Language Programming
Thus you can use BLO, BHI, BLS, or BHS after a CMP instruction to compare
the magnitude of unsigned numbers. There are four branches so that you can put the
equality case on either side; that is, the options are:
a. (A) > (M) BHI, branch if (A) is higher (greater than (M)).
b. (A) :> (M) BHS (BCC) branch , if (A) is higher or same (greater than or equal
to (M)).
c. (A) <i. (M) BLS, branch if (A) is lower or same (less than or equal to (M)).
d. (A) < (M) BLO (BCS), branch if (A) is lower (less than (M)).
where OLD PC is the original value of the program counter and the extra 2 comes from
the two bytes occupied by the branch instruction itself. Rearranging, we can calculate
the offset from the equation
OFFSET = NEW PC - OLD PC - 2
So
OFFSET = 0008 - 0004 - 2 - 02
You can always get the same result by counting bytes. Start counting at at the byte
address is smaller than the original program counter value plus two. Then you must deal
with negative binary or hexadecimal numbers: FF 16 is —1, FE 16 is —2, and so on.
Counting bytes is very tedious, especially for long offsets.
The way assembler do it. You can, for
to avoid calculating offsets is to let the
example, simply specify how far you want the branch to go by using an expression
containing the symbol *, which refers the assembler to the current value of the location
counter. Thus
BHS *+4
will produce a branch to the instruction four bytes further along. The assembler will take
care of the extra 2 automatically (that is, it will make the actual offset 2 instead of 4).
The problem with this approach is that 6809 instructions vary in length and thus it is
often difficult to determine the required numerical value. Furthermore, a much better
method of specifying offsets is available.
4
Conditional Branches
1. If the condition is true, the processor branches. That is, it places the destina-
tion address in the program counter and starts executing instructions at that
point.
the branch instruction did nothing at all except advance the program counter.
Sample Problem:
(0040) = 67
(0041) = 2A
(0042) = 1
(0043) = F8
Program 4-8:
0000 DC 40 LDD $40 GET FIRST 16-BIT NUMBER
0002 D3 42 ADDD $42 ADD SECOND 16-BIT NUMBER
0004 DD 44 STD $44 STORE 16-BIT RESULT
0006 3F SWI
4-8 6809 Assembly Language Programming
Entry
Hexadecimal
Memory Address Hexadecimal Decimal
0050 00 (02)
0051 01 1 2
(1 )
0052 04 4 (22)
0053 09 9 (32)
0054 10 16 (42)
0055 19 25 (5 2 )
0056 24 36 (6 2 )
0057 31 49 (7 2 )
Sample Problems:
a. (0041) = 03
Result: (0042) = 09
b. (0041) = 06
Result: (0042) = 24
Program 4-9:
0000 D6 41 LDB $41 GET DATA
0002 8E 0050 LDX #$50 GET BASE ADDRESS
0005 A6 85 LDA B,X GET SQUARE OF DATA
0007 97 42 STA $42 STORE SQUARE
0009 3F SWI
The assembler directive FCB places the table of squares in memory locations 0050
through 0057. This block of data is essential for the proper execution of the program,
even though it does not consist of instructions. The object program may thus include
fixed data as well as executable instructions.
LDX # $50 loads Index Register X from the two bytes of memory immediately
following the operation code (addresses 0003 and 0004 in the object program). The pro-
cessor loads the contents of the first byte into the eight most significant bits of Index
Register X, and the contents of the second byte into the eight least significant bits of
Index Register X. Always remember that Index Registers X and Y, Stack Pointers S and
U, and the Double Accumulator D are all 16 bits long.
Indexed Addressing
The instruction LDA B,X loads Accumulator
from the address calculated by A
adding the contents of Index Register X and the con-
(the "base address" of the table)
tents of Accumulator B (the index of the element that we want). For example, if
memory location 0041 contains 03, then
(X) = 0050 (base address of the table of squares)
(B) = 03 (data)
must actually perform some computations (perhaps even involving another table) to
determine an index from the data.
The use of tables represents tradeoffs among programming time, execution
time, and memory usage. A table lookup executes faster than any but the simplest
calculations. For example, even the Table of Squares program executes faster than an
equivalent simple squaring program using the 6809 multiplication instruction MUL.
Tables can be faster and simpler to program than actual calculations since lookup pro-
cedure^ do not depend on the complexity of the function involved. Furthermore, since a
table lookup is fast-executing, it js unlikely to slow down a program intolerably, as a
complex calculation might, and thus is less likely than a calculation to require
reprogramming to save execution time. On the other hand, tables can occupy a large
Beginning Programs 4-11
amount of memory if there are many possible input values. We can often reduce the
required amount of memory by limiting the accuracy of the results, scaling the input
data, or organizing the table cleverly.
Common uses of tables include the computation of transcendental and trig-
onometric functions, the linearization of inputs from thermocouples and other non-
linear devices, and code conversions.
Sample Problem:
(0040) = 67
= 011 ° ° 111 111 ° 0010 2
(0041) E2 f
Result: (0042) = 98 )
1001 1000 0001 1101 z
(0043) = ID f
The ones complement of a number is its logical inverse; that is, each bit in the
number is replaced by a 1 and each 1 bit by a 0. The sum of a number and its ones com-
plement is therefore always a number in which all the bit positions contain Is.
Program 4-10:
0000 DC 40 LDD $40 GET 16-BIT NUMBER
0002 43 COMA ONES COMPLEMENT MSB'S
0003 53 COMB ONES COMPLEMENT LSB'S
0004 DD 42 STD $42 STORE 16-BIT ONES COMPLEMENT
0006 3F SWI
Despite the 6809's 16-bit instructions, you must use the 8-bit instructions to per-
form many arithmetic and logical operations. The 6809 instruction set does include
some common 16-bit operations, such as loading, adding, comparing, subtracting, and
storing, but other operations must be performed eight bits at a time.
Manage the accumulators with care; they can hold only one result at a time. If you
need an accumulator's contents, be sure to save them before reloading the accumulator.
PROBLEMS
4-1. 16-BIT DATA TRANSFER
Purpose: Move the contents of memory location 0040 to memory location 0042 and the
contents ofmemory location 0041 to memory location 0043.
Sample Problem:
(0040) = 3E
(0041) = B7
Result: (0042) = 3E
(0043) = B7
4-12 6809 Assembly Language Programming
Sample Problem:
(0040) = 77
(0041) = 39
Result: (0042) = 3E
Sample Problem:
Sample Problem:
Sample Problem:
(0040) = 6A = 0110 1010 2
(0041) = B3 = 1011 001 2
Result: (0042) = A3 = 1010 OO1 2
Beginning Programs 4-13
Sample Problems:
(0040) 3F
(0041) 2B
Result: (0042) = 2B
(0040) 75
(0041) A8
Result: (0042) = 75
Sample Problem:
(0040) = 35)
(0041) = 67} 35672A
(0042) = 2a/
(0043) = 51)
(0044) = A4> 51A4F8
(0045) = F8J
Result: (0046) = 87)
(0047) = OC 870C22
(0048) = 22;
Sample Problem:
(0040) = 03
(0041) 06
Result: (0042) - 20
that is, 32 + 62 = 9 + 36 10 = 45 10 2D,
4-14 6809 Assembly Language Programming
Sample Problems:
"'
So4i! = oof
01 " oo 10 oooo 000 °!
REFERENCES
1. L. A. Leventhal, "Microprogramming," Kilobaud, April 1977, pp. 120-23.
5
Simple Program Loops
The program loop is the basic structure that forces the CPU to repeat a
sequence of instructions. Loops have four sections:
The computer performs Sections 1 and 4 only once, while it may perform Sections
2 and 3 many times. Therefore, the execution time of the loop depends mainly
on the
execution time of Sections 2 and Those sections should execute as quickly as possible,
3.
while the execution times of Sections 1 and 4 have little effect on overall program speed.
Figures 5-1 and 5-2 contain two alternative flowcharts for a typical program
loop. Following the flowchart in Figure 5-1 results in the computer always executing
the processing section at least once. On the other hand, the computer may not execute
the processing section in Figure 5-2 at all. The order of operations in Figure 5-1 is
more natural, but the order in Figure 5-2 is often more efficient and eliminates the prob-
lem of the computer going through the processing sequence once even where there is no
data for it to handle.
The computer can use the loop structure to process large sets of data (usually
called "blocks" or "arrays"). The simplest way to use one sequence of instructions
to handle a block of data is to have the program add 1 to its address register (usually
5-2 6809 Assembly Language Programming
C Start
J
Initialization
Section
Processing
Section
Loop Control
Section
Concluding
Section
c End
3
The computer always executes the processing section at least once.
an index register or stack pointer) after each iteration. Then the address register will
contain the address of the next element in the block when the computer repeats the
sequence of instructions. The computer can then handle blocks of any length with a
single program.
Indexed addressing is the key to processing blocks of data with the 6809
microprocessor, since that mode allows you to vary the actual address of the data (the
"effective address") by changing the contents of an address register. In immediate and
extended addressing modes, the instruction completely determines the effective
address; that address is therefore fixed if program memory is read-only. The direct page
mode shares this fixed address limitation even though a register determines part of the
effective address.
The 6809's autoincrementing mode is particularly convenient for processing
arrays, since it automatically updates the address register for the next iteration. No
Simple Program Loops 5-3
C Start
J
1
Initialization
Section
3
Loop Control
Section
Yes
Processing Concluding
Section Section
c End
}
The computer need not execute the processing section at all if it finds that there is nothing to be done.
ing (subtracting 1 or 2 before each iteration). Most programmers find moving back-
wards through an array somewhat awkward and difficult to follow, but it is more effi-
cient in many situations. Clearly, the computer does not know backwards from forward.
The programmer, however, must remember that the 6809 increments an address
register after using it but decrements an address register before using it. This
difference affects initialization as follows:
PROGRAM EXAMPLES
5-1. SUM OF DATA
Purpose: Calculate the sum of a series of numbers. The length of the series is in
memory location 0041 and the series begins in memory location 0042. Store
the sum in memory location 0040. Assume that the sum is an 8-bit number so
that you can ignore carries.
Sample Problem:
(0041) = 03
(0042) = 28
(0043) = 55
(0044) = 26
Result: (0040) = A3
28, + 55 1fi + 26 1
There are three entries in the sum, since (0041) =03
Flowchart:
f Start
J
SUM =
POINTER = 0042
COUNT = (0041)
SUM =
3
SUM + (POINTER)
POINTER =
I
POINTER + 1
COUNT =
COUNT - 1
(0040) = SUM
C End
)
Simple Program Loops 5-5
Program 5-1 a:
0000 4F CLRA SUM = ZERO
0001 D6 41 LDB $41 COUNT = LENGTH OF ARRAY
0003 8E 0042 LDX #$42 POINT TO START OF ARRAY
0006 AB 80 SUMD ADDA ,X+ ADD NUMBER TO SUM
0008 5A DECB
0009 26 FB BNE SUMD
000B 97 40 STA $40
000D 3F SWI
The initialization section of the program consists of the first three instructions,
which set the sum, counter, and data pointers to their starting values. LDX loads the
two bytes of memory into Index Register X: 00 and 42 from memory addresses 0004 and
0005 respectively.
The processing section of the program consists of the single instruction
ADDA ,X+ which adds the contents of the memory location addressed by Index
Register X to the contents of Accumulator A. This instruction does the real work of the
program. The effective address (that is, the address from which the CPU gets the data)
is given by the contents of Index Register X.
In the autoincrementing mode, the processor adds 1 to the contents of Index
Register X after using to fetch the data. For example, in the first iteration, Index
it
Register X initially contains 0042. The execution of the instruction ADDA ,X+ results
in the contents of memory location 0042 being added to Accumulator A, and Index
Register X
being incremented by 1 to 0043.
The loop control section of the program consists of the single instruction DECB,
since the instruction ADDA
,X+ updates the pointer automatically. DECB decrements
the counter that keeps track of how many iterations the computer has left to perform.
The instruction BNE causes a branch if the Zero flag is (that is, if the result of
decrementing B was not zero). The offset is a twos complement number, determined by
the distance between the destination and the end of the instruction. In this case, the dis-
tance is from memory location 000B (the address following the end of the BNE instruc-
tion) to memory location 0006 (the destination). So the offset is:
0006 1 _( 0006
-OOOB )(+FFF5
FF FB _
The 8-bit offset mode (BNE rather than LBNE) requires only the two least significant
digits of the difference.
If the Zero flag is 1 (that is, if the result of decrementing B was zero), the processor
continues its normal sequence. Thus the result of executing BNE is:
(SUMD if the result of decrementing B is not zero
The extra 2, as usual, comes from the two bytes occupied by the BNE instruction itself.
Most programmers make computer loops count down rather than up so that
they can use the setting of the Zero flag as an exit condition. Remember that the Zero
flagis 1 if the most recent result was zero and if that result was not zero. Rewrite the
program so that it loads Accumulator B with zero initially and increments it after each
iteration. Which approach is more efficient?
The order in which the processor executes instructions is often very important.
DECB must come immediately before BNE SUMD; otherwise, the intervening instruc-
tion (s) would probably change the Zero flag. The order of operations within instructions
may also be important. In the current program, we must initialize Index Register X to
0042, the lowest address in the array, since the processor increments Index Register X
after using its contents in the instruction ADDA
,X + What initial value would be
.
necessary if the processor incremented Index Register X before using its contents?
Using Register Y
We could easily use Index Register Y, User Stack Pointer U, or Hardware
Stack Pointer S instead of Index Register X. The only difference is that LDS and LDY
require two-byte operation codes, so a program using one of those registers would
occupy one additional byte of memory and would take one extra clock cycle to execute.
For example, the following program uses Index Register Y.
Program 5-1 b:
0000 4F CLRA SUM = ZERO
0001 D6 41 LDB $41 COUNT = LENGTH OF ARRAY
0003 108E 0042 LDY #$42 POINT TO START OF ARRAY
0007 AB A0 SUMD ADDA #Y+ ADD NUMBER TO SUM
0009 5A DECB
000A 26 FB BNE SUMD
000C 97 40 STA $40
000E 3F SWI
In most applications, the slight differences in execution time and memory usage
between the two programs do not matter. However, you might as well use Index
Register X rather than Index Register Y when both are available, since programs that
use Index Register X will be a little shorter and faster. User Stack Pointer U can also be
utilized as an address register, but most programs leave Hardware Stack Pointer S
permanently assigned for use with subroutines and interrupts.
You should verify the hexadecimal value of the relative offset in the last program
example. Of course, the final test of any calculation of an offset is whether the program
runs correctly. If you must perform hexadecimal calculations frequently, you should
consider purchasing either a manual aid or a calculator such as the Texas Instruments
Programmer.
Sample Problem:
(0042) 03
(0043) C8
(0044) FA
(0045) 96
Result: (0040) 02
(0041) 58 | 0258 16
- C8 16 + FA 16 + 96 1(
Flowchart:
f Start
J
SUMU =
SUML =
POINTER = 0043
COUNT = (0042)
ISUML*
SUML+ (POINTER)
SUMU=
SUMU+CARRY
POINTER =
I
POINTER + 1
COUNT =
COUNT - 1
(0040) = SUMU
(0041) = SUML
I
C End
D
SUMU and SUML are, respectively, the high-order and low-order bytes of the 16-
bit sum, SUM.
Program 5-2:
0000 4F CLRA MSB'S OF SUM = ZERO
0001 5F CLRB LSB'S OF SUM = ZERO
0002 8E 0043 LDX #$43 POINT TO START OF ARRAY
0005 EB 80 ADDB ,X+ SUM = SUM + DATA
0007 89 00 ADCa #0 AND ADD IN CARRY
0009 OA 42 DEC $42
000B 26 F8 BNE SUMD
000D DD 40 STD $40 SAVE SUM
000F 3F SWI
5-8 6809 Assembly Language Programming
This program has the same structure as the previous example. The only difference
is that thisprogram must handle the high-order byte of the sum as well as the low-order
byte. The initialization section clears the full 16-bit sum and the processing section now
consists of two instructions: ADDB ,X+
adds the 8-bit data to the low-order byte of the
sum and ADCA #0 adds the carry to the high-order byte.
The only new aspect is that the 16-bit sum occupies both accumulators. Thus we
use a memory location on the direct (base) page to hold the counter. Such memory
locations are often used as they were additional registers, since the processor can
if
access them with faster and shorter instructions than those it uses to access other
locations.
The instruction ADCA #0 adds the carry and to Accumulator A:
(A) = (A) + + Carry
= (A) + Carry
The result is to leave A unchanged if the Carry flag is and to increment A by 1 if the
Carry flag is 1.
The 6809 does not have a complete set of 16-bit instructions. For example, there
is no Clear Double Accumulator instruction. We can use either the two instructions
CLRA, CLRB (requiring two bytes of memory and four clock cycles) or the immediate
instruction LDD #0 (requiring three bytes of memory and three clock cycles).
However, when a 16-bit instruction is available (for instance, STD $40), it uses less
time and memory than the two equivalent 8-bit instructions (in this case, STA $40, STB
$41).
A single DEC
$42 can decrement the contents of a memory
instruction such as
location by 1 without changing any registers. Such instructions do affect the flags,
however. Note that a memory location is not nearly as useful as an accumulator; there
are no instructions that perform general arithmetic or logical operations on data in a
memory location. For example, SUBA #3 subtracts 3 from Accumulator A; try to per-
form the same operation on the data in memory location 0042.
For longer distances, you must use the long form of the branches. A long condi-
tional branch uses the same mnemonic as its short equivalent, with an additional
"L" in front: for instance, LBCC instead of BCC. It requires a two-byte operation code
followed by a two-byte relative offset. However, the unconditional branch LBRA has a
one-byte operation code, although it still requires a two-byte offset. The long relative
branches provide access to any memory location in the normal 64K range. In actual
practice, most program branches are quite short and you will rarely need the long
forms.
Simple Program Loops 5-9
Sample Problem:
(0041) = 06
(0042) = 68
(0043) = F2
(0044) = 87
(0045) = 30
(0046) = 59
(0047) = 2A
Result: (0040) = 02, since 0043 and 0044 contain
numbers with an MSB of 1
Flowchart:
c Start
J
NNEG =
POINTER = 0042
COUNT = (0041)
POINTER =
POINTER + 1
COUNT =
COUNT - 1
(0040) = NNEG
C End
Z>
6-10 6809 Assembly Language Programming
Like the previous flowchart, this one takes the form shown in Figure 5-1; thus it
Program 5-3:
the distance from the end of the instruction to the destination. Here the distance is a
single byte; the result is that the processor skips the INCB instruction if the Sign flag
isO.
The Sign simply reflects the value of bit 7 of the most recent result. If you
flag
are using signednumbers, bit 7 is, in fact, the sign (0 for positive, 1 for negative); the
mnemonics for Branch if Sign = 1 (BMI) and Branch if Sign = (BPL) assume that
you are using signed numbers. However, you can equally well use bit 7 for other pur-
poses, such as the status of peripherals or other one-bit data. You can still test bit 7 with
BMI BPL; the mnemonics may no longer make sense, but the operations work. The
or
computer performs its operations without considering whether the user thinks they are
sensible or meaningful. The interpretation of the results is the programmer's problem,
not the computer's.
Negative signed numbers all have a most significant bit of 1 and thus are
actually larger, in the unsigned sense, than positive numbers.
Sample Problem:
(0041) = 05 Number of elements
(0042) = 67
(0043) = 79
(0044) = 15
(0045) = E3
(0046) = 72
Result: (0040) = E3, since this is the largest of
Flowchart:
c Start
J>
COUNT = (0041)
POINTER = 0042
MAX =
POINTER =
POINTER + 1
COUNT =
COUNT - 1
Program 5-4:
0000 D6 41 LDB $41 COUNT = NUMBER OF ELEMENTS
0002 4F CLRA MAX = (MINIMUM POSSIBLE)
0003 8E 0042 LDX #$42 POINT TO FIRST ENTRY
0006 Al 80 MAXM CMPA IS CURRENT ENTRY GREATER
THAN MAX?
0008 24 02 BHS NOCHG
000A A6 IF LDA -lfX YES, REPLACE MAX WITH
CURRENT ENTRY
oooc 5A NOCHG DECB
000D 26 F7 BNE MAXM
000P 97 40 STA $40 SAVE MAXIMUM
0011 3F SWI
The first three instructions of this program form the initialization section.
This program takes advantage of the fact that zero is the smallest unsigned binary
number. If you make zero the initial estimate of the maximum, the program will set the
maximum to a larger value unless all the elements in the array are zeros.
1 1
The instruction LDA — 1,X uses the indexed addressing mode with a constant
The offset of —1 is necessary because the autoincrementing in CMP A ,X+ has
offset.
added 1 to Index Register X. The object code uses the special 5-bit offset form (signified
by a in bit 7 of the post byte). In this form, the offset is a twos complement number in
the five least significant bits; bit 4 is thus the sign of the offset, and the processor auto-
more significant positions before performing
matically extends (copies) that bit into the
the addition.The processor thus extends 1 1 1 1 2 to 1111 1111 2 an 8-bit number. This ,
form requires no additional bytes of memory (since the post byte contains the offset)
and only one additional clock cycle. The range of the offset is
-16 10 = 10000 2 £ Offset < +15 10 = 0111 2
1. BHS NOCHG
Destination address = OOOC
- Address at end of instruction = 000A
02
2. BNE MAXM
Destination address = 0006 - 0006
- Address at end of instruction = 000F + FFF1
F7
The program works correctly if the array has two elements, but not if it has only one ele-
ment or none at all. Why? How could you eliminate this problem?
The instruction CMP A ,X + affects the Carry flag as follows (ELEMENT is the
contents of the effective address and MAX is the contents of Accumulator A):
If Carry = 0, the program branches to address NOCHG and does not replace the current
maximum. If Carry= 1, the program replaces the maximum with the current element
using the instruction LDA — 1,X.
The program does not work properly if the numbers are signed, because negative
numbers all appear to be larger than positive numbers. You must then use the Sign
(Negative) flag instead of the Carry in the comparison. However, you must also con-
sider the fact that twos complement overflow can affect the sign; that is, the magnitude
of a signed result could overflow into the sign bit. The 6809 has special branch instruc-
tions — BGT, BGE, BLE, and BLT — which perform the branches indicated by their
mnemonics after signed comparisons and handle twos complement overflow auto-
matically.
Sample Problems:
(0040) = 22
Result: (0041) 88
(0042) = 02
(0040) = 01
Result: (0041) = 80
(0042) 07
(0040) = CB
Result: (0041) = CB
(0042) 00
(0040) = 00
Result: (0041) 00
(0042) _ 00
Flowchart:
I [ Start )
NSHFT =
NUMB = (0040)
^r ls^^ Yes
^^^ ?
pNo
/ls^s^ Yes .J f
^Vbit of NUMB^
ITno <
'
Shift NUMB
left one bit (0041) = NUMB
NSHFT = (0042) = NSHFT
NSHFT + 1
,
i
C_i id
J
Program 5-5a:
0000 5F CLRB NUMBER OF SHIFTS = ZERO
0001 96 40 LDA $40 GET DATA
0003 27 06 BEQ DONE THROUGH IF DATA IS ZERO
0005 2B 04 CHKMS BMI DONE THROUGH IF MSB OF DATA IS
0007 5C INCB ADD 1 TO NUMBER OF SHIFTS
0008 48 AS LA SHIFT DATA LEFT ONE BIT
0009 20 FA BRA CHKMS
000B DD 41 DONE STD $41 SAVE JUSTIFIED DATA AND
NUMBER OF SHIFTS
000D 3F SWI
5-14 6809 Assembly Language Programming
1. BEQ DONE
Destination address = OOOB
- Address at end of instruction = 0005
06
2. BMI DONE
Destination address = OOOB
- Address at end of instruction = 0007
04
3. BRA CHKMS
Destination address = 0005 = 0005
Address at end of instruction = OOOB = +FFF5
FA
ASL (Arithmetic Shift Left) shifts the contents of the specified accumulator or
memory one bit and clears the least significant bit. The most significant bit
location left
ends up in the Carry flag and the old Carry value is lost. ASLA is equivalent to adding
Accumulator A to itself; the result is, of course, twice the original number (try it!).
BMI DONE causes a branch to address DONE if the Sign flag is 1 . This condition
may mean that the result was a negative number, or it may just mean that the most sig-
nificant bit of that result was 1 The computer only performs the operations; the pro-
.
counter. The 6809also has the unconditional jump instruction JMP, which can use
direct (base page), extended, or indexed addressing. BRA, like the conditional branch
instructions, always uses relative addressing.
Program 5-5b:
This version initializes the number of shifts to — 1 and shifts the data until the
Carry becomes 1. Then it shifts the data back once since the last shift was not really
necessary. Show that this version is also correct. What are its advantages and disadvan-
tages as compared to the other version? You might wish to try some other organizations
to see how they compare in terms of execution time and memory usage.
)
PROBLEMS
5-1. CHECKSUM OF DATA
Purpose: Calculate the checksum of a series of numbers. The length of the series is in
memory location 0041, and the series itself begins in memory location 0042.
Store the checksum in memory location 0040. The checksum is formed by
Exclusive-ORing all the numbers in the series together.
Such checksums are often used in paper tape and cassette systems to ensure that
the data has been read correctly. The calculated checksum is compared to the one stored
with the data — if the two checksums do not agree, the system will usually either indi-
cate an error to the operator or automatically read the data again.
Sample Problem:
(0041) = 03
(0042) 28
(0043) = 55
(0044) 26
Result: (0040) (0042) © (0043) © (0044)
28 © 55 ©
26
0010 1000
© 0101 0101
0111 1101
© 0010 0110
0101 1011
_ 5B
mation does not result in any carries (i.e., the sum is a 16-bit number).
Sample Problem:
(0042) = 03 Length of the Array
(0043) ~ 8
p | 28F1, First Number in Array
(0044)
(0045) ae 30
. . > 301 A, Second Number in Array
(0046) = 1A)
(0047) = 4B^ 4B89
- ' Tnird Number in Arra y
(0048) 89 f
Result: (0040) = A4) A4g4 =
28M + 3Q1A + 4B8g
(0041) = 94K J
Sample Problem:
(0043) = 06
(0044) = 68
(0045) = F2
(0046) = 87
(0047) = 00
(0048) = 59
(0049) = 2A
Result: 2 negative, 1 zero, and 3 positive, so
(0040) = 02
(0041) = 01
(0042) = 03
Sample Problem:
(0041) = 05
(0042) = 67
(0043) = 79
(0044) = 1
(0045) = E3
(0046) = 72
Result: (0040) = 1 5, since this is the smallest of the
five unsigned numbers
Sample Problem:
(0040) = 3B = 0011 1011 2
Result: (0041) = 05
6
Character-Coded Data
1. The codes for thenumbers and letters form ordered subsequences. Since the
ASCII codes for the numbers through 9 are 30 16 through 39 16 you can con-
,
vert a decimal digit to the equivalent ASCII character (and ASCII to decimal)
by means of a simple additive factor: 30 16 = ASCII 0. Since the codes for the
upper-case letters (41 16 through 5A 16 ) are ordered alphabetically, you can
alphabetize strings by sorting them according to their numerical values.
\MSBs
\ 1 2 3 4 5 6 7 Control Characters
LSBs\
NUL DLE SP (3 P ,
E SO RS > N *
n — SO Shift out US Unit separator
F SI US / ? DEL SI Shift in SP Space
DLE Data link escape DEL Delete
3. An ASCII I/O device handles data only in ASCII. For example, if you want
an ASCII printer to print the digit 7, you must send it 37, 6 as the data; 07 is
16
the "bell" character. Similarly, if an operator presses the "9" key on an
ASCII keyboard, the input data will be 39 16 ; 09 16 is the "horizontal tab"
character.
4. Many ASCII devices do not use the entire character set. For example,
devices may ignore meaningless control characters and may not print lower-
case letters.
5. ASCII control characters often have widely varying interpretations. Each
ASCII device typically uses control characters in a special way to provide
features such as cursor control on a CRT, and to allow software control of
characteristics such as rate of data transmission, print width, and line length.
Each ASCII character occupies eight bits. This allows a large character set
but is wasteful when only a few characters are actually being used. If, for
example, the data consists entirely of decimal numbers, the ASCII format
(allowing one digit per byte) requires twice as much storage, communications
capacity, and processing time as does the BCD format (allowing two digits per
byte).
Character-Coded Data 6-3
PROGRAM EXAMPLES
6-1. LENGTH OF A STRING OF CHARACTERS
Purpose: Determine the length of a string of characters. The string starts in memory
location 0041; the end of the string is marked by an ASCII carriage return
character OCR', 0D 16 ). Place the length of the string (excluding the carriage
return) into memory location 0040.
Sample Problems:
a. (0041) OD
Result: (0040) = 00 sin<
b. (0041) = 52 'R'
(0042) s 41 'A'
(0043) = 54 T'
(0044) = 48 'H'
(0045) = 45 'E'
(0046) SB 52 'R'
(0047) s OD CR
Result: (0040) = 06
Flowchart:
c Start
D
POINTER = 0041
LENGTH =
Yes
LENGTH =
LENGTH + 1
(0040) = LENGTH
POINTER =
POINTER + 1
C End
}
Program 6-1 a:
0000 5F CLRB STRING LENGTH = ZERO
0001 8E 0041 LDX #$41 POINT TO START OF STRING
0004 86 OD LDA #$0D GET ASCII CARRIAGE RETURN
* (STRING TERMINATOR)
0006 Al 80 CHKCR CMPA ,X+ IS NEXT CHARACTER
* A CARRIAGE RETURN?
0008 27 03 BEQ DONE YES, END OF STRING
000A 5C INCB NO, ADD 1 TO STRING LENGTH
000B 20 F9 BRA CHKCR
000D D7 40 DONE STB $40 SAVE STRING LENGTH
OOOF 3F SWI
6-4 6809 Assembly Language Programming
As far as the computer is concerned, the carriage return (CR) is just another
ASCII code (0D 16 ). The fact that the carriage return causes the output device to per-
form a control function rather than print a symbol does not affect the computer.
The Compare instruction CMP performs a subtraction and sets the flags, but
does not change the contents of the accumulator. In Program 6- la, CMP A leaves the
carriage return character in Accumulator A for later use. In this program, the CMPA
instruction affects the Zero flag as follows:
Z = 1 if the character in the string is a carriage return
Z = if it is not a carriage return
Flowchart:
c Start
3
POINTER = 0041
LENGTH = -1
LENGTH =
LENGTH + 1
POINTER =
(0040) = LENGTH
POINTER + 1
C End
}
Character-Coded Data 6-5
Program 6-1 b:
0000 C6 FF LDB #$FF STRING LENGTH = -1
0002 8E 0041 LDX #$41 POINT TO START OF STRING
0005 86 OD LDA #$0D GET ASCII CARRIAGE RETURN
(STRING TERMINATOR)
0007 5C CHKCR INCB ADD 1 TO STRING LENGTH
0008 Al 80 CMPA ,x+ IS NEXT CHARACTER
A CARRIAGE RETURN?
000A 26 FB BNE CHKCR NO, KEEP CHECKING
000C D7 40 STB $40 YES, SAVE STRING LENGTH
000E 3F SWI
This program, like the previous one, has no provision for stopping if a maximum
string length is reached before a carriage return is found.
Sample Problem:
(0042) = 37 '7'
(0042) = 20 SP
(0043) = 20 SP
(0044) = 20 SP
(0045) = 46 •F
(0046) = 20 SP
Result: (0040) =
~ 00)
\ since the three previous memory locations all contain blanks
(0041) = 45 J
Flowchart:
c Start
J
POINTER = 0042
C End
6-6 6809 Assembly Language Programming
Program 6-2:
0000 8E 0042 LDX #$42 POINT TO START OF STRING
0003 86 20 LDA #' GET ASCII SPACE FOR COMPARISON
0005 Al 80 CHBLK CMPA ,x+ IS CHARACTER AN ASCII SPACE?
0007 27 FC BEQ CHBL YES, KEEP EXAMINING CHARS
0009 30 IF LEAX -1,X NO, MOVE POINTER BACK ONE
000B 9F 40 STX $40 SAVE ADDRESS OF FIRST
NON-BLANK CHARACTER
000D 3F SWI
Note the use of an apostrophe (') or single quotation mark before an ASCII
character.
Looking for spaces in strings is a common task in microprpcessor applications.
Programs often reduce storage requirements by removing spaces that only serve to
increase readability or fit data into particular formats. Storing and transmitting extra
space characters obviously wastes memory, communications capacity, and processor
time. However, operators find it easier to enter data and programs when the computer
accepts extra spaces; the entry is then said to be in free, rather than fixed, format. One
of themost popular uses of microcomputers is to convert data and commands between
the forms that are easy for people to handle and the forms that are most efficient for
computers and communications systems.
The LEA instruction has many uses in 6809 programming. This instruction
calculates an effective address using one of the indexed addressing modes (see
Chapter 22 for a complete description), but then simply places that address in an
index register or stack pointer rather than using it to transfer data. The effective
address is available for later use and need not be recalculated. This can
save execution
time. Remember that instructions using most of the indexed addressing modes, particu-
larly more complicated modes, require many additional clock cycles to execute.
the
Furthermore, the programmer can later use the effective address in any of the indexed
modes, thus providing additional levels of indirection and more flexibility.
LEA can perform many simple functions. For example, you can (as in Program
6-2) subtract 1 from Index Register X with the instruction
LEAX -1,X
In this case, the processor first calculates the effective address by adding
-1 to the con-
Register X. A more
tents of Index Register X. It then places that result back in Index
complex example is one that adds 8 to User Stack Pointer U and places the result in
LEAY 8,U
the index register one beyond the end of the array when autodecrementing.
Character-Coded Data 6-7
Sample Problems:
(0040) = 02 Length of the string in bytes
(0041) = 36 *6'
(0042) = 39 '9'
The program leaves the string unchanged, since the leading digit is not zero
(0041) = 30 '0'
(0042) = 30 '0'
= '8'
(0043) 38
Result: (0041) = 20 SP
(0042) = 20 SP
The program replaces the two leading zeros with ASCII spaces.
Flowchart:
c Start
COUNT = (0040)
POINTER = 0041
POINTER =
POINTER + 1
(POINTER - 1 )
=
SP(=20 16 )
COUNT =
COUNT - 1
6-8 6809 Assembly Language Programming
Program 6-3:
ful to leave one zero if all the digits in the string are zero. How would you modify the
program to do this?
We have assumed that the length of the string (the contents of location 0040) will
be greater than zero. What will happen if (0040) = 00 when the program starts execu-
tion?
The instruction STB - 1, X places an ASCII space (20 16 ) in a memory location that
previously contained ASCII zero. Here again we need the offset of - 1 to make up for
We have assumed that all the digits in the string are in the ASCII form; that is, the
digits used are 30 16 through 39, 6 rather than the ordinary decimal to 9. Converting a
digit from BCD to ASCII is simply a matter of adding 30 16 (ASCII zero), while convert-
ing from ASCII to decimal involves subtracting the same number.
You can place a single ASCII character in a 6809 assembly language program
by preceding it with an apostrophe ('). You can place a string of ASCII characters in
program memory by using the FCC (Form Constant Characters) directive on the 6809
assembler. There are two acceptable forms of this directive:
EMSG FCC 5 , ERROR
In the form, the user must specify the number of characters, followed by a comma
first
and the character string. In the second form, the user may place any single character
delimiter (we will always use /) at both ends of the string.
Each ASCII digit requires eight bits of storage, as compared to four bits for a
BCD digit. Therefore, ASCII is a relatively expensive format in which to store or
transmit numerical data.
Sample Problem:
(0040) = 06 Length of string
Flowchart:
C Start
J
POINTER = 0041
COUNT = (0040)
BITCOUNT =
DATA = (POINTER)
POINTER =
POINTER + 1
BIT COUNT =
BIT COUNT + 1
(LSB = 0)
6-10 6809 Assembly Language Programming
Program 6-4:
0000 8E 0041 LDX #$41 POINT TO START OF DATA BLOCK
0003 A6 80 GTBYTE LDA »x+ GET A BYTE OF DATA
0005 5F CLRB BIT COUNT » ZERO INITIALLY
0006 48 CHBIT AS LA SHIFT A DATA BIT TO CARRY
0007 C9 00 ADCB #0 IF BIT IS 1, INCREMENT
* BIT COUNT
0009 40 TSTA KEEP COUNTING UNTIL
* DATA BECOMES ZERO
000A 26 FA BNE CHBIT
OOOC 54 LSRB DID DATA HAVE EVEN NUMBER
* OF 'l' BITS?
000D 24 06 BCC NEXTE
000F A6 IF LDA -lfX NO, SET EVEN PARITY BIT
* IN DATA
0011 8A 80 ORA #%10000000
0013 A7 IF STA -i»x
0015 OA 40 NEXTE DEC $40
0017 26 EA BNE GTBYTE
0019 3F SWI
Sample Problems:
a. (0041) = 03 Number of characters in each string
(0042) as 43 *c
(0043) = 41 'A'
(0044) = 54 v
(0052) = 43 *c*
(0053) ss 41 'A'
(0054) = 54 T
Result: (0040) = 00. since the two strings are the si
(0052) s 43 'C
(0053) s 41 'A'
(0054) = 54 •v
Result: (0040) = FF. since the first characters in the
strings differ
Note: The matching process ends as soon as the CPU finds a difference — the rest of the
stringsneed not be examined.
Program 6-5:
Program 6-5 autoincrements both Index Register X and Index Register Y. Note
that LDY requires a 2-byte operation code, while LDX requires only a 1-byte code. In
fact, the operation code for LDY is the operation code for LDX preceded by the byte
10 16 . The prefix byte 10 16 apparently tells the 6809 processor that this instruction falls in
a special group and the next byte will actually describe the operation to be performed.
We
could replace CLR $40 with INC $40 or STB $40 (why?). Which of these
alternatives executes faster? Which do you think is clearer?
Flowchart:
C Start
J
POINTER 1 = 0042
POINTER2 = 0052
COUNT = (0041)
MARK = FF 16
POINTER 1 =
POINTER 1 + 1
P0INTER2 =
POINTER2 + 1
COUNT =
COUNT - 1
MARK =
(0040) = MARK
c End
}
»
PROBLEMS
6-1. LENGTH OF A TELETYPEWRITER MESSAGE
Purpose: Determine the length of an ASCII message. All characters are 7-bit ASCII
with MSB = 0. The which the message is embedded
string of characters in
starts in memory location 0041. itself starts with an ASCII STX
The message
character (02 16 ) and ends with ETX (03 16 ). Place the length of the message
(the number of characters between the STX and the ETX but including
neither) into memory location 0040.
Sample Problem:
(0041) = 40
(0042) = 02 STX
(0043) = 47 'G'
= '0*
(0044) 4F
(0045) = 03 ETX
Result: (0040) = 02, since there are two characters between
the STX in location 0042 and ETX in
location 0045
Sample Problems:
(0042) = 37 T
(0043) = OD CR
Result. (0040) = 00 since the last (and only)
sin non-blank
(0041) = 42 S cha
character is in memory location 0042
(0042) = 41 'A'
(0043) = 20 SP
(0044) = 48 'H'
(0045) = 41 'A'
(0046) = 54 'T'
(0047) = 20 SP
(0048) = 20 SP
(0049) = OD CR
Result: (0040) = 00
(0041) = 46
6-14 6809 Assembly Language Programming
Sample Problems:
(0041) 37 •T
(0042) 2E
(0043) - 38 •8'
(0044) 31 'V
Result: (0041) 37 •T
(0042) = 2E
(0043) 20 SP
(0044) 20 SP
(0040) = 03 Length of string
(0041) 36 6'
(0042) = 37 •T
(0043) 31 'V
Result: Unchanged, as number is assumed to be 671
Sample Problems:
Sample Problems:
(0042) = 43 c
(0043) = 41 'A'
(0044) = 54 T
(0052) = 42 'B'
(0053) = 51 'A'
(0054) = 54 'T'
(0042) = 43 'C
(0043) = 41 'A'
(0044) = 54 •v
(0052) = 43 C
(0053) = 41 'A'
(0054) = 54 T
Result. (0040) = 00, since the two strings are equal
(0042) = 43 'C
(0043) s 41 'A*
(0044) = 54 'T
(0052) = 43 c
(0053) = 55 U'
(0054) = 54 'T'
2. More complex conversions can be handled with lookup tables. The lookup
table method requires little programming and is easy to apply. However, the
table may occupy a large amount of memory if the range of input values is
large.
In most applications, the program should do as much as possible of the code con-
version work. This approach reduces parts count and power dissipation, saves board
space, and increases reliability. Furthermore, most code conversions are easy to pro-
gram and require little execution time.
7-2 6809 Assembly Language Programming
PROGRAM EXAMPLES
7-1. HEXADECIMAL TO ASCII
Purpose: Convert the contents of memory location 0040 to an ASCII character.
Memory location 0040 contains a single hexadecimal digit (the four most sig-
nificant bits are zero). Store the ASCII character in memory location 0041.
Sample Problems:
(0040) = OC
Result: (0041) = 43 'C
(0040) = 06
Result: (0041) = 36 '6'
Program 7-1:
digits. This addition converts the digits through 9 to ASCII correctly. However, the
letters A through F do not follow immediately after the digit 9 in the ASCII code;
instead, there is a break between the ASCII code for 9 (39 16 ) and the ASCII code for A
(41 16 ), so the conversion must add a further constant to the nondecimal digits (A, B,
C, D, E, and F) to account for the break. The first ADD instruction does this by adding
'A — '9 — 1 to Accumulator A. Can you explain why the extra factor for letter digits
has the value 'A - '9 - 1?
We have used the ASCII forms for the addition factors in the source program; a
single quotation mark (apostrophe) before a character indicates the ASCII equivalent.
We have also left the offset for the letters as an arithmetic expression to make its mean-
ing as clear as possible. The extra assembly time is a small price to pay for the great
increase in clarity. A routine like this is necessary in many applications; for example,
monitor programs must convert hexadecimal ASCII equivalents in order
digits to their
Try this program on some hexadecimal digits. Can you explain why it works?
Code Conversion 7-3
Flowchart:
c Start
}
I
DATA - (0040)
DATA =
DATA + ASCII A
- ASCII 9 - 1
I
RESULT =
DATA + ASCII
(0041) = RESULT
End
C
Sample Problems:
(0041) = 03
Result: (0042) = 4F
(0041) = 28
Result: (0042) = 00
Program 7-2:
0000 5F CLRB GET ERROR CODE
TO BLANK DISPLAY
0001 96 41 LDA $41 GET DATA
-0003 81 09 CMPA #9 IS DATA A DECIMAL DIGIT?
0005 22 05 BHI DONE NO, KEEP ERROR CODE
0007 8E 0020 LDX #SSEG YES, GET SEVEN-SEGMENT
CODE FROM TABLE
000A E6 86 LDB A,X
OOOC D7 42 DONE STB $42
000E 3F SWI
with 8-bit microprocessors. However, many people find seven-segment coded digits
somewhat difficult toTead, although their widespread use in calculators and watches
has made them more familiar.
Flowchart:
c Start
DATA = (0041)
r DATA > 9 ^
Xno "
RESULT =
(SSEG + DATA) RESULT =
(0042) = RESULT
C End
D
Note that the addition of base address (SSEG) and index (DATA) produces the
address that contains the answer.
Digit Cods
3F
1 06
2 5B
3 4F
4 66
5 6D
6 7D
7 07
8 7F
9 6F
7 6 5 4 3 2 1 Bit Number
1" g f e d c b •1 Code
Sample Problems:
(0040) - 37'7'
Result: (0041) = 07
Result: (0041) FF
Flowchart:
C Start
1
DATA (0040)
V^> ASCII 9/
• No < '
RESULT - RESULT - FF 16
DATA - ASCII
J—
(0041) = RESULT
C End
}
Code Conversion 7-7
Program 7-3:
0000 C6 FF LDB #$FF GET ERROR MARKER
0002 96 40 LDA $40 GET DATA
0004 80 30 SUB A #'0 IS DATA BELOW ASCII ZERO?
0006 25 06 BLO DONE YES, NOT A DIGIT
0008 81 09 CMPA #9 IS DATA ABOVE ASCII NINE?
000A 22 02 BHI DONE YES, NOT A DIGIT
000C IF 89 TFR A,B SAVE VALID DECIMAL DIGIT
OOOE D7 41 DONE STB $41 SAVE DIGIT OR ERROR MARKER
0010 3F SWI
This program handles ASCII-coded characters just like ordinary numbers. Since
ASCII assigns an ordered sequence of codes to the decimal digits, we can identify an
ASCII character as a digit by determining if it falls within the proper range of
numerical values. We could use the order of ASCII codes similarly to determine if a
character is in a particular group of letters or symbols, such as A through F. This
approach assumes detailed knowledge of a particular code and would not necessarily
be valid for other codes.
Subtracting ASCII (30 16 ) from any ASCII decimal digit gives the decimal
value of that digit. An ASCII character is a decimal digit if its value lies between 30 l6
and 39 16 (including the endpoints); how would you determine if an ASCII character is a
valid hexadecimal digit? ASCII-to-decimal conversion is necessary in applications in
which decimal data is entered from an ASCII device such as a teletypewriter or terminal.
The program performs one comparison — to the lower limit — with an actual
subtraction (SUB A #'0) since the subtraction is necessary for the ASCII-to-decimal
,
conversion. It performs the other comparison with an implied subtraction (CMPA #9)
to avoid destroying the possible decimal digit in Accumulator A. Implied subtractions
(CMP) are far more common than actual subtractions (SUB) in programs, since the
numerical value of the result is seldom of interest.
The instruction TFR can transfer the contents of any 8- or 16-bit register to any
other 8- or 16-bit register. TFR copies the source register into the destination register;
the source register not changed. The only restriction is that the source and destina-
is
tion registers must be the same length (both eight bits long or both 16 bits long). TFR
instructions always require one byte besides the operation code; the high-order four bits
of that byte specify the source register and the low-order four bits specify the destination
register.See the description of TFR in Chapter 22 for more details.
One special use of TFR is to load the direct page register, since there is no LD
instruction for that register. A typical sequence that loads the direct page register with
the constant value PGNO is:
Sample Problems:
(0040) = 02
(0041) = 09
(0042) = 1D 16 =
(0040) = 07
(0041) = 01
Program 7-4:
0000 96 40 LDA $40 GET MOST SIGNIFICANT DIGIT
0002 C6 0A LDB #10 MULTIPLY BY 10
0004 3D MUX
0005 DB 41 ADDB $41 ADD LEAST SIGNIFICANT DIGIT
0007 D7 42 STB $42 STORE BINARY EQUIVALENT
0009 3P SWI
decimal numbers using repeated additions. 2 The instruction ASLA multiplies the con-
tents of Accumulator A by 2, so multiplications by powers of 2 can be implemented as
arithmetic shifts.
Sample Problem:
(0041) = D2 = 1101 0010
Result: (0042) = 31 •v
(0043) = 31 •y
(0044) = 30 •0'
(0045) = 31 'V
(0046) = 30 '0'
= '0'
(0047) 30
(0048) = 31 •y
(0049) = 30 '0'
Code Conversion 7-9
Flowchart:
c Start
J
DATA = (0041)
POINTER = 0042
^
(POINTER) = ASCII
Shift DATA right
one bit
POINTER =
POINTER + 1
Program 7-5:
Since the decimal digits form a sequence in ASCII, ASCII 1 = ASCII 0+1.
The CMP (X/Y/U/S/D) instructions compare 16-bit quantities.flags are The
set according to the result of the entire 16-bit subtraction, even though the
microprocessor actually performs it eight bits at a time. CMPX
takes two cycles longer
7-10 6809 Assembly Language Programming
than CMPA or CMPB, while CMPD, CMPY, CMPS, and CMPU all require two-byte
operation codes and take three cycles longer than CMPA or CMPB.
Single-operand instructions like INC, DEC, COM, or ASL can all use any of
the indexed addressing modes. Be careful of the fact that such instructions affect
memory locations (the effective address), not the specified index register or stack
pointer (except through autoincrementing or autodecrementing). For example, CLR
,X+ clears the byte of memory located at the address in Index Register X (and
autoincrements X); it does not clear Index Register X.
Assembly-time arithmetic often comes in handy for performing address com-
parisons. If, for example, we established that the ASCII binary string started in the loca-
This form is and easier to change than is an explicit address. Furthermore, the
clearer
programmer does not have to perform any hexadecimal arithmetic.
Binary-to- ASCII conversion is necessary if numbers are to be printed in binary
on an ASCII device. Binary outputs are helpful in debugging and testing when each
bit has a separate meaning; typical examples are inputs from a set of panel switches or
outputs to a set of LEDs. If the programmer can only obtain the value in some other
number system (such as octal or hexadecimal), he or she must perform an error-prone
hand conversion to check the bits.
PROBLEMS
7-1. ASCII TO HEXADECIMAL
Purpose: Convert the contents of memory location 0040 to a hexadecimal digit and
store the result in memory location 0041. Assume that memory location 0040
contains the ASCII representation of a hexadecimal digit (7 bits with MSB 0).
Sample Problems:
(0040) = 43 'C
Result: (0041) = 0C
(0040) = 36 '6'
Result: (0041) = 06
the seven-segment table given in Figure 7-1 and try to match codes.
1
Sample Problems:
(0040) = 4F
Result: (0041) = 03
(0040) = 28
Result: (0041) = FF
Sample Problems:
(0040) = 07
Result: (0041) = 37 '7'
(0040) = 55
Result: (0041) = 20 SP
Sample Problems:
(0040) = 1D = 29 10
Result: (0041) = 02
(0042) = 09
(0040) = 47 = 71.
Result: (0041) = 07
(0042) = 01
Sample Problems:
(0042) = 31 '1*
(0043) = 31 'V
(0044) = 30 '0'
= '1'
(0045) 31
(0046) = 30 '0'
(0047) = 30 •0'
(0048) a 31 *r
'0'
(0049) 30
Result: (0041) = D2 = 1101 0010
(0040) = 00
REFERENCES
1. D. R. Allison, "A Design Philosophy for Microcomputer Architectures," Com-
puter, February 1977, pp. 35-41. This is an excellent article which we highly recom-
mend.
2. Other BCD-to-binary conversion methods are discussed in J. A. Tabb and M. L.
Roginsky, "Microprocessor Algorithms Make BCD-Binary Conversions Super-
fast," EDN, January 5, 1977, pp. 46-50, and in J. B. Peatman, Microcomputer-Based
Design, (New York: McGraw-Hill, 1977), pp. 400-406.
8
Arithmetic Problems
PROGRAM EXAMPLES
8-1. MULTIPLE-PRECISION BINARY ADDITION
Purpose: Add two multi-byte binary numbers. The length of the numbers (in bytes) is
in memory location 0040, the numbers themselves start (least significant bits
first) in memory locations 0041 and 0051 respectively, and the sum replaces
Sample Problem:
(0040) 04 Number of bytes in each number
(0041) C3
(0042) A7
2F5BA7C3 16 is first number
(0043) 5B
(0044) 2F
(0051) B8 )
(0052) 35 (
Result: (0041) 7B
(0042)
?9 > 443ADD7B 16 issum
(0043)
(0044) - 44
Flowchart:
f Start
J
COUNT =
7 (0040)
POINTER 1 = 0041
P0INTER2 * 0051
CARRY =
(P0INTER1) =
(P0INTER1 ) +
(P0INTER2) +
(CARRY) (This step also produces new carry)
P0INTER1 =
P0INTER1 + 1
P0INTER2 =
P0INTER2 + 1
COUNT = COUNT -1
c End
D
Arithmetic Problems 8-3
Program 8-1
0000 D6 40 LDB $40 COUNT= LENGTH OF NUMBER IN BYTES
0002 8E 0041 LOX #$41 POINT TO LSB'S OF FIRST NUMBER
0005 108E 0051 LDY #$51 POINT TO LSB'S OF SECOND NUMBER
0009 1C FE ANDCC #%11111110 CLEAR CARRY TO START
000B A6 84 ADBYTE LDA ,X GET BYTE FROM FIRST NUMBER
000D A9 AO ADCA ,Y+ ADD BYTE FROM SECOND NUMBER
000F A7 80 STA ,X+ STORE RESULT IN FIRST NUMBER
0011 5A DECB
0012 26 F7 BNE ADBYTE CONTINUE UNTIL ALL BYTES ADDED
0014 3F SWI
The instruction ANDCC logically ANDs the next byte of program memory with
the condition code register, clearing those flags that are ANDed with 'O's and leaving
unchanged those flags that are ANDed with 'l's. ANDCC #%1 1 1 1 1 1 10 thus clears bit
of the condition code register (the Carry flag) and leaves the other bits unchanged.
The 6800 mnemonic for this operation is much clearer — CLC (CLEAR CARRY); of
course, the 6809 ANDCC is more general. The program must clear the carry since there
is never a carry into the least significant bytes.
The instruction ORCC
is similar to ANDCC, except that it logically ORs the
next byte of program memory with the condition code register, setting those flags that
are ORed with 'l's and leaving unchanged those flags that are ORed with '0's. ORCC
#%00000001 thus sets bit of the condition code register (the Carry flag) and leaves the
other bits unchanged. As with ANDCC, the 6800 version of this operation mnemonic is
much clearer - SEC (SET CARRY).
Positioning Data
This program uses two index registers so that the two numbers can be positioned
independently in memory. If we used a single index register, the numbers could be
located anywhere but would always have to be separated by a constant distance. We
could take advantage of the User Stack Pointer U to store the result in a third indepen-
dent set of memory locations. You might try modifying the program so that it stores the
sum starting in memory location 0061.
One shortcoming of the 16-bit instruction ADDD is that it cannot be extended easily.
There is no 16-bit equivalent of the ADD WITH CARRY instruction.
Sample Problem:
(0040) = 04 Number of bytes in each number
(0041) = 85
(0042) = 19
= 36701985 is first number
(0043) 70
(0044) = 36
(0051) = 59
(0052) = 34
=
1 2663459 is second number
(0053) 66
(0054) = 12
Result: (0041) = 44
(0042) = 54
49365444 is decimal sum
(0043) = 36
(0044) = 49
that is. 36701985
+ 12663459
49365444
Flowchart:
Start
c J>
COUNT = (0040)
POINTER 1 = 0041
P0INTER2 = 0051
Carry =
(POINTER 1) =
(POINTER 1) (This step also
+ (P0INTER2) produces new carry)
+
Carry
+ Decimal Correction
POINTER 1 =
POINTER 1 + 1
P0INTER2 =
P0INTER2 + 1
COUNT = COUNT-I
End
c J>
Arithmetic Problems 8-5
Program 8-2:
0000 D6 40 LDB $40 COUNT=LENGTH OF NUMBERS IN BYTES
0002 8E 0041 LDX #$41 POINT TO LSB'S OF FIRST NUMBER
0005 108E 0051 LDY #$51 POINT TO LSB'S OF SECOND NUMBER
0009 1C FE ANDCC #%11111110 CLEAR CARRY TO START
000B A6 84 ADDIGS LDA ,X GET TWO DIGITS OF FIRST NUMBER
000D A9 AO ADCA ,Y+ ADD TWO DIGITS OF SECOND NUMBER
000F 19 OAA DECIMAL CORRECTION
0010 A7 80 STA ,X+ STORE RESULT IN FIRST NUMBER
0012 5A DECB
0013 26 F6 BNE ADDIGS CONTINUE UNTIL ALL DIGITS ADDED
0015 3F SWI
The Decimal Adjust (DAA) instruction uses the Carry (C) and Half-Carry (H)
flags to recognize and change the following situations in which binary and BCD addition
differ:
1. The sum of two digits is between 10 and 15 inclusive. In this case, six must
be added to the sum to give the right result, e.g.,
0101 (5)
+ 1000 (8)
1101 (D)
+ 0110
0001 001 1 (BCD 13, which is correct)
The sum of two digits is 16 or more. In this case, the result is a proper BCD
digit but six less than it should be, e.g.,
1000 (8)
+ 1001 (9)
nize Case 1 by determining that the sum is not a BCD digit, i.e., it is between 10 and 15
(or A and F hexadecimal). On the other hand, the processor must check the digit carry
(H for the lower digit, C for the upper digit) to recognize Case 2, since the result is a
valid BCD DAA the only instruction that actually needs the H (Half-Carry)
number. is
flag. Note that DAA only operates on Accumulator A and only works correctly after an
operation;if, for example, X and Y are each two digits from a string of
decimal numbers, then
X-Y = X + 99-Y + BORROW
where BORROW is the borrow from the previous (less significant) digits.
3. INC or DEC, since neither affects the Half-Carry or the Carry. You can,
however, perform a decimal increment of Accumulator A with the sequence:
The decimal increment produces a carry if the result is 100, while the decimal
decrement produces a carry unless the result is 99. Thus you can recognize
either a carry or a borrow by examining the Carry flag.
4. LEA, since it produces a 16-bit result and does not affect either the Half-
Carry flag or the Carry flag.
12 x 4 = 48 bits
as compared to 40 bits using binary addition. This is six bytes instead of five, a 20%
increase.
Arithmetic Problems 8-7
Sample Problems:
(0040) = 03 multiplier
(0041) = 00
= [ 0005 is multiplicand
(0042) 05
Result: (0043) = 00 )
(0040) 64 multiplier
(0041) 75
7530 is multiplicand
(0042) 30
Result: (0043) 20
(0044) C6 2DC6C0 is product
(0045) CO
or in decimal: 100 x 30.000 = 3.000.000.
Program 8-3:
Extending the MUL instruction to handle longer operands works much like ordin-
You must be careful to align the partial products correctly before
ary long multiplication.
adding them together. Each successive partial product is shifted 8 bits to the left from
the previous product. The ADCA #0 instruction provides a convenient way to handle
carries thatmay result from adding partial products.
Besides its obvious uses in calculators and point-of-sale terminals, multiplica-
tion is also a key part of almost all signal processing and control algorithms. The
speed at which a processor can perform multiplication determines its usefulness in
process control, adaptive control, signal detection, and signal analysis.
Multi-Dimensional Arrays
station number and sensor number, we generally refer to the reading from the 7th sen-
sor at station number 5 as R(5,7), where R is the name of the entire array. The usual
method of storing such an array is to start at address RBASE with R(0,0) and continue
1
with R(0,1), R(0,2), etc. If there are 3 stations (0, 1, and 2) and 4 sensors at each sta-
tion (0, 1, 2, and 3), we keep the readings in the following memory locations:
RBASE R(O.O)
RBASE + 1 R|0,1)
RBASE + 2 R(G,2)
RBASE + 3 R(0,3)
RBASE + 4 R(1.0)
RBASE + 5 RI1.1)
RBASE + 6 RI1.2)
RBASE + 7 R(1,3)
RBASE + 8 R(2,0)
RBASE + 9 R(2,1)
RBASE + 10 R(2,2)
RBASE + 11 R(2,3)
In general, if we know the station number I and the sensor number J, the reading
R(I,J) is located at address
RBASE + N x | + J
where N the number of sensors at each station. Thus locating a particular reading in
is
order to update it, display it, or perform some mathematical operations on it requires a
multiplication. For example, the operator might want an instrument to print the current
reading of sensor #3 at station #2. To find that reading, the processor must calculate the
address
Even more multiplications are necessary if the array has more dimensions. For
example, we might organize the sensors by station number, position in the X direction,
and position in the Y direction (each station thus has sensors at regular positions on a
two-dimensional surface). Now we can describe a reading R(2,3,l), which refers to the
reading of the sensor at station #2, X position #3, and Y position #1. We can add even
more dimensions, such as vertical position, type of sensor, or time of reading. Each
added dimension means that the processor must perform more multiplications to locate
elements in the essentially one-dimensional memory.
Execution Time
This algorithm takes 54 clock cycles (or 27 microseconds if the clock is 2 MHz) to
multiply on a 6809 microprocessor. Higher speed would require additional hardware,
such as one of the multiplier chips described in the References at the end of this chapter.
Sample Problems:
(0040) = 00
(0041) = 40 J 0040i6 = 64isdividend
(0042) = 08 divisor
(0040) 32
326D 6
= 1 2,909 is dividend
(0041) 6D 1
(0042) 47 7 10 is divisor
Division Algorithm
You can perform division on the computer just as you would perform division
with pen and paper, i.e., using trial subtractions. Since the numbers are binary, the
only question is whether the bit in the quotient is or 1, i.e., whether the divisor can be
subtracted from what is left of the dividend. Each step in a binary division can be
reduced to the following operation:
If the divisor can be subtracted from the eight most significant bits of the dividend
without a borrow, the corresponding bit in the quotient is 1; otherwise, it is 0.
The only remaining problem is to line up the dividend and quotient properly.
You can do by shifting the dividend and quotient logically left one bit before each
this
trial subtraction. The dividend and quotient can share a 16-bit register, since the pro-
cedure clears one bit of the dividend at the same time as it determines one bit of the
quotient.
The complete process for binary division is
STEP 1 — Initialization
QUOTIENT =
COUNT = 8
COUNT = COUNT - 1
IfCOUNT ^ 0, GO TO STEP 2
REMAINDER = 8 MSBs of DIVIDEND
In the case of sample problem b, where the dividend is 326D 16 and the divisor is
DIVIDEND 19D0
DIVISOR 47
QUOTIENT OB
COUNT 04
The MSBs of dividend and divisor are assumed to be zero to simplify calculations
(the shift prior to the trial subtraction would otherwise place the MSB of the dividend in
the Carry). Problems that are not in this form must be simplified by removing parts of
the quotient that would overflow an 8-bit word. For example:
The last problem is now in the proper form. An extra division may be necessary.
1
Flowchart:
c Start
1
DIVIDEND =
(0040): (0041)
DIVISOR = (0042)
COUNT = 8
QUOTIENT =
DIVIDEND = 2 >
DIVIDEND
QUOTIENT = 2
QUOTIENT (Shift both left 1 bit)
8 MSBs of
DIVIDEND = 8 MSBs
of DIVIDEND-
DIVISOR
QUOTIENT =
QUOTIENT
OTJENJ + 1
COUNT =
COUNT - 1
(0043) =
8 MSB's of
DIVIDEND =
REMAINDER
(0044) = QUOTIENT
C End
J
Program 8-4:
(LSRD).
Accumulators and B hold both the dividend and the quotient. The quotient
A
simply replaces the dividend in Accumulator B as the dividend is shifted left logically.
(2 in each byte) starts in memory location 0042. Calculate the checksum digit
by the Double Add Double Mod 10 technique and store it in memory loca-
1
tion 0040.
The Double Add Double Mod 10 technique works as follows:
Self-Checking Numbers
Self-checking digits are commonly added to identification numbers on credit
cards, inventory tags, luggage, parcels, etc. when they are handled by computerized
systems. They may also be used in routing messages, identifying files, and other
applications. The purpose of the digits is to minimize entry errors such as transpos-
ing digits (69 instead of 96), shifting digits (7260 instead of 3726), missing digits by
one (65 instead of 64), etc. You can check the self-checking number automatically for
correctness upon entry and can eliminate many errors immediately.
The analysis of self-checking methods is quite complex. For example, a plain
Arithmetic Problems 8-13
checksum will not find transposition errors (4 + 9 = 9 + 4). The Double Add Double
549321
the result will be:
Checksum = 5X2 + 4+9x2 + 3 + 2x2+1= 40
Self-checking digit = (least significant digit of checksum)
Note that an erroneous entry like 543921 would produce a different self-checking digit
(4), but erroneous entries like 049321 or 945321 would not be detected.
Sample Problems:
(0041) = 03 Number of bytes
(0042) = 36
(0043) = 68
(0044) = 51
(0042) = 50
(0043) = 29
(0044) = 16
(0045) = 83
Result: Checksum = 5 X2 + + 2X2 + 9 + 1 X2 + 6 + 8x2 + 3 = 50
(0040) = 00
Program 8-5:
0000 8E 0042 LDX #$42 POINT TO START OF STRING
0003 OF 40 CLR $40 CHECKSUM=ZERO
0005 A6 84 CHKDG LDA ,X GET NEXT 2 DIGITS OF DATA
0007 44 LSRA SHIFT OFF LEAST SIGNIFICANT
* DIGIT
0008 44 LSRA
0009 44 LSRA
000A 44 LSRA
000B IF 89 TFR A,B COPY MOST SIGNIFICANT DIGIT
000D 9B 40 ADDA $40 ADD MSD TO CHECKSUM
000F 19 DAA RETAINING DECIMAL FORM
0010 97 40 STA $40
0012 IF 98 TFR B,A AND ADD MSD TO CHECKSUM AGAIN
0014 9B 40 ADDA $40
0016 19 DAA RETAINING DECIMAL FORM
0017 AB 80 ADDA ,X+ ADD IN LEAST SIGNIFICANT DIGIT
0019 19 DAA RETAINING DECIMAL FORM
001A 97 40 STA $40
001C OA 41 DEC $41 CONTINUE UNTIL ALL DIGITS ADDED
001E 26 E5 BNE CHKDG
0020 84 OF ANDA #%00001111 SAVE LSD OF CHECKSUM
0022 97 40 STA $40
0024 3F SWI
8-14 6809 Assembly Language Programming
Flowchart:
f Start
J
T
CHECKSUM =
COUNT = (0041)
POINTER = 0042
MSD=(POINTER)-M 6
LSD = (POINTER)
AND00001111,2
CHECKSUM =
CHECKSUM +
2 * MSPfLSP
"|Pt
POINTER =
POINTER + 1
COUNT =
COUNT - 1
(0040) -
CHECKSUM AND
00001 111 2
End
C
Four logical right shifts move the most significant digit to the least significant bit
positions. There is no reason to mask out the most significant digit before adding the
least significant digit, since we do not care what happens to the most significant digit of
the checksum anyway.
A decimal adjust (DAA) must follow each addition to produce the proper
decimal result. A single DAA after a series of additions will not work (try it!).
Remember that DAA only operates on Accumulator A.
There is no problem with carries from the various decimal sums, since the
algorithm only uses the least significant digit of the checksum anyway.
You cannot use ASLA, because it leaves the Half-Carry flag undefined. Only
ADCA, ADCB, ADDA, and ADDB set the Half-Carry flag correctly.
You can number by 2 simply by shifting it right logically and
divide a decimal
then subtracting 3 from any digit that has a value of 8 or larger (since 10 BCD is 16, ).
The following program divides a decimal number in memory location 0040 by 2 and
places the result in memory location 0041.
Binary Rounding
Rounding numbers is simple, regardless of whether they are binary or decimal.
You can round a binary number as follows:
If the most significant bit to be dropped is 1, add 1 to the remaining bits. Other-
wise, do not change the remaining bits.
This rule works because 1 is halfway between and 10 in binary, much as 5 is halfway in
decimal (0.5 decimal = 0.1 binary).
So the following program will round a 16-bit number in memory locations 0040
and 0041 (MSB's in 0040) to an 8-bit number in memory location 0040:
TST $41 IS MSB OF EXTRA BYTE 1?
BPL DONE
INC $40 YES, ROUND UP
DONE SWI
The TST instruction sets the flags according to the contents of the specified
accumulator or memory location (by subtracting zero from those contents), thus allow-
ing you to change the flags without using any registers or changing any values.
If the number is longer than 16 bits, the rounding must ripple through the other
bytes as needed. Of course, the only time the rounding affects the more significant bytes
is when it causes a carry. Since incrementing a memory location with INC does not affect
the Carry flag, we can only recognize a carry by checking to see if the result of INC is
zero. The following program increments a 16-bit number in memory locations 0040 and
0041 (MSB's in 0040).
This approach is more general, since the step size can have any value.
8-16 6809 Assembly Language Programming
Decimal Rounding
Decimal rounding is a bit more difficult, because the crossover point is now
BCD 50 and the rounding must produce a decimal result. The rule is:
If the most significant digit to be dropped is 5 or more, add 1 to the remaining
digits.
The following program will round a four-digit BCD number in memory locations
0040 and 0041 (MSD's in 0040) to a two-digit BCD number in memory location 0040.
LDA $41 IS BYTE TO BE DROPPED 50 OR MORE?
CMPA #$50
BLO DONE
LDA $40 YES, ADD 1 TO MSD'S
ADDA #1 KEEPING THEM IN DECIMAL FORM
DAA
STA $40
DONE SWI
Remember that you cannot use INC to add 1 because INC does not affect the
Half-Carry flag (which could have any value). As in the binary case, rounding longer
numbers requires that the carries ripple through the more significant digits as needed.
PROBLEMS
8-1. MULTIPLE-PRECISION BINARY SUBTRACTION
Purpose: Subtract one multi-byte binary number from another. The length of the num-
bers (in bytes) is in memory location 0040, the numbers themselves start
(least significant bits first) in memory locations 0041 and 0051 respectively,
and the difference replaces the number starting in memory location 0041.
Subtract the number starting in 0051 from the one starting in 0041.
Sample Problem:
(0041) = C3
(0042) = A7
=
2F5BA7C3 16 is minuend
(0043) 5B
(0044) = 2F
(0051) = B8
(0052) = 35
=
1 4DF35B8 6 is subtrahend
(0053) DF 1
(0054) = 14
Result: (0041) = OB
(0042) = 72
=
1 A7C720BT 6 is difference
(0043) 7C
(0044) = 1A
Sample Problem:
(0040) 04 Number of bytes
(0041) 85
(0042) 19
36701985 is minuend
(0043) 70
(0044) 36
(0051) 59
(0052) 34
1 2663459 is subtrahend
(0053) 66
(0054) 12
Result: (0041) 26
(0042) 85
24038526 is decimal difference
(0043) 03
(0044) 24
where X and Y are each two digits from the decimal strings and BORROW is the borrow
from the less significant digits. The right-hand side of this equation has an extra factor of
100, but that factor has no effect on a two-digit number. Note, however, that the opera-
tions on the right-hand side produce an overall carry if X — Y + BORROW is positive
but not if it is negative or zero.
Sample Problems:
K
(0042)
:
=
si""--*-
00
0005 is multiplicand
(0043) = 05 f
Result: (0044) = 00
(0045) = 00
= OOOOOOOF is product
(0046) 00
(0047) = OF
or in decimal: 3x5 = 15.
(0040) 27
2710 is multiplier
(0041) 10
(0042) 75
7530 is multiplicand
(0043) 30
Result: (0044) 11
(0045) E1
11E1A300 is product
(0046) A3
(0047) 00
or in decimal: 10,000 x 30,000 = 300,000,000.
7
Sample Problems:
(0040)
CQ { dividend is -64 10
(0041)
(0042) = 08 divisor
b. (0040) = ED ) .. .. ..
,,_, .
dividends -4.71
(0041) = 93 \ 10
(0042) = 47 divisor is 71 10
Hint:Determine the sign of the result, perform an unsigned division, and finally
adjust the quotient and remainder to the proper forms. <
549321
Sample Problems:
a. (0041) = 03 Number of bytes
(0042) = 36
(0043) = 68
(0044) = 51
(0042) = 50
(0043) = 29
(0044) = 1
(0045) = 83
EL4 Result: Checksum = 5 + 3x0+7x2 + 9 + 3x1+7X6 + 8 + 3x3- 90
(0045) = 00
Hint: Note that 7 = 2 x 3 + 1 and 3 = 2 x 1 + 1, so the formula Mj =2 x M_
i 1
+ 1 can be used to calculate
the next multiplying factor.
REFERENCES
1. J. R. Herr. "Self-Checking Number Systems," Computer Design, June 1974, pp.
85-91.
2. Other methods for implementing multiplication, division, and other arithmetic,
tasks are discussed in:
AH, Z. "Know the LSI Hardware Tradeoffs of Digital Signal Processors," Electronic
Design, June 21, 1979, pp. 66-71.
Geist, D. J. "MOS Processor Picks up Speed with Bipolar Multipliers," Electronics,
July 7, 1977, pp. 113-115.
Kolodzinski, A. and D. Wainland. "Multiplying with a Microcomputer," Electronic
Design, January 18, 1978, pp. 78-83.
Tables and lists are two of the basic data structures used with all computers.
We have already seen tables used to perform code conversions and arithmetic. Tables
may also be used to identify or respond to commands and instructions, linearize data,
provide access to files or records, define the meaning of keys or switches, and choose
among alternate programs. Lists are usually less structured than tables. Lists may
record tasks that the processor must perform, messages or data that the processor
must record, or conditions that have changed or should be monitored. Tables are a
simple way of making decisions or solving problems, since no computations or logical
functions are necessary. The task, then, reduces to organizing the table so that the
proper entry is easy to find. Lists allow the execution of sequences of tasks, the prepara-
tion of sets of results, and the construction of interrelated data (or data bases). Problems
include how to add elements to a list and remove elements from it.
PROGRAM EXAMPLES
9-1. ADD ENTRY TO LIST
Purpose: Add the contents of memory location 0040 to a list if it is not already present
in the list. The length of the list is in memory location 0041 and the list itself
Sample Problems:
(0040) = 6B Entry to be added
(0043) = 61
(0044) s 38
(0045) = 1D
Result: (0041) = 05 New length
(0046) = 6B
The entry 6B is added to the list, since it is not already there. The length of the list is
increased by 1.
(0043) = 6B
(0044) = 38
(0045) = 1D
Result: No change, since the entry (6B) is already in the list (in memory location 0043)
Flowchart:
c Start
D
ENTRY = (0040)
COUNT = (0041)
POINTER = 0042
POINTER =
POINTER + 1
COUNT =
COUNT - 1
(POINTER) = ENTRY
(0041) = (0041)
+ 1
£
C End
}
Tables and Lists 9-3
Program 9-1:
0000 8E 0042 LDX #$42 POINT TO START OF LIST
0003 D6 41 LDB $41 COUNT - LENGTH OF LIST
0005 96 40 LDA $40 GET ENTRY
0007 Al 80 SRLST CMPA ,x+ IS ENTRY - ELEMENT IN LIST?
0009 27 07 BEQ DONE YES, DONE
000B 5A DECB ALL ENTRIES EXAMINED?
000C 26 F9 BNE SRLST NO, KEEP LOOKING
000E A7 84 STA ,x YES, ADD ENTRY TO LIST
0010 OC 41 INC $41 ADD 1 TO LIST LENGTH
0012 3F DONE SWI
Clearly, this method of adding elements is very inefficient if the list is long. We
could improve the procedure by limiting the search to part of the list or by ordering the
list. We could limit the search by using the entry to get a starting point in the list. This
method is called "hashing," and is much like selecting a starting page in a dictionary or
directory on the basis of the first letter in an entry. We could order the list by numerical
>
value. The search could then end when the list values went beyond the entry (larger or
smaller, depending on the ordering technique used). A new entry would have to be
inserted properly, and all the other entries would have to be moved down in the list.
The program could be restructured to use two tables. One table could provide a
starting point in the other table; for example, the search point could be based on the
most or least significant 4-bit digit in the entry.
The program does not work if the length of the list could be zero (what happens?).
We could avoid this problem by checking the length initially. The initialization pro-
cedure would then be:
LDB $41 COUNT = LENGTH OF LIST
BEQ ADELM ADD ENTRY TO LIST IF LENGTH IS ZERO
Unlike some other processors, the 6809's Zero flag is affected by simple data transfer
instructions such as LD and ST (store).
(load)
If each entry were more than one byte in length, a pattern-matching program
would be necessary. The program would have to proceed to the next entry if a match
failed; that is, skip over the last part of the current entry once a mismatch was found.
Sample Problems:
(0041) - 6B Entry to be added
(0042) - 04 Length of list
(0044) 55
(0045) 7D
(0046) S Al
Result: (0040) = FF, since 6B is not in the list
9-4 6809 Assembly Language Programming
(0044) = 55
(0045) = 6B
(0046) A1
Result: (0040) - 00. since 6B is in the list
Flowchart:
c Start
3
ENTRY = (0041)
POINTER = 0043
COUNT = (0042)
MARK =
POINTER =
POINTER + 1
COUNT = MARK = FF 16
COUNT - 1
(0040) = MARK
C End
3
The searching process is a bit different here since the elements are ordered. Once
we find an element larger than the entry, the search is over, since subsequent elements
will be even larger. You may want to try an example to convince yourself that the pro-
cedure works. Note that an element larger than the entry is indicated by a comparison
that produces a borrow (that is, Carry =1).
As in the previous problem, a table or other method that could choose a good
starting point would speed up the search. One method would be to start in the middle
and determine which half of the list the entry was in, then divide the half into halves,
etc. This method is called a binary search, since it divides the remaining part of the list in
half each time. 2 - 3
Tables and Lists 9-5
Program 9-2:
0000 OF 40 CLR $40 NARK ELEMENT AS IN LIST
0002 8E 0043 LDX #$43 POINT TO START OF LIST
0005 D6 42 LDB $42 COUNT " LENGTH OF LIST
0007 96 41 LOA $41 GET ENTRY
0009 Al 80 SRLST CMPA ,x+ IS ENTRY EQUAL TO ELEMENT?
000B 27 07 BEQ DONE YES, DONE
OOOD 25 03 BCS NOTIN ENTRY NOT IN LIST IF ELEMENT
* IS LARGER
OOOF 5A DECB ALL ELEMENTS EXAMINED?
0010 26 F7 BNE SRLST
0012 03 40 NOTIN COM $40 YES, MARK ELEMENT AS NOT I
0014 3F DONE SWI LIST
This algorithm is a bit slower than the one in Program 9-1 because of the extra
conditional jump (BCS NOTIN). The average execution time for this simple search
technique increases linearly with the length of the list, while the average execution time
for a binary search increases logarithmically.For example, if the length of the list is
doubled, the simple technique takes twice as long on the average, while the binary
search method only requires one extra iteration.
Queues are used to store data in the order in which it will be used, or tasks in
the order in which they will be executed. The queue is a first-in, first-out data struc-
ture; i.e., elements are removed from the queue in the same order in which they were
entered. Operating systems place tasks in queues so that they will be executed in the
proper order. I/O drivers transfer data to or from queues so that it will be transmitted or
handled in the proper order. Buffers may be queued so that the next available one can
easily be found and those that are released can easily be added to the available storage.
Queues may also be used to link requests for storage, timing, or I/O so that they can be
satisfied in the correct order.
In real applications, each element in the queue will typically contain a large
amount of information or storage space besides the address required to link the ele-
ment to the next one.
Sample Problems:
(0042) = 00
Address
{• of first element in queue
(0043) = 46
(0046) = 00 > Address of second element in queue
(0047) f
(004D)
End of queue
(004E) = 00 |
Result: (0040) = 00
Address of element removed from queue
(0041) = 46
(0042)
{• Address of new first element in queue
(0043)
)
(0042)
| Empty queue
i
(0043)
Flowchart:
C Start
POINTER =
(0042): (0043)
(0040): (0041) =
POINTER
(0042) = (POINTER)
(0043) =
(POINTER + 1
( ™ )
Program 9-3:
0000 9E 42 LDX $42 GET ADDRESS OF HEAD OF QUEUE
0002 9F 40 STX $40 REMOVE HEAD OF QUEUE
0004 27 04 BEQ DONE DONE IF QUEUE WAS EMPTY
0006 AE 84 LDX ,x GET ADDRESS FROM NEXT ELEMENT
0008 9F 42 STX $42 MOVE NEXT ELEMENT TO HEAD OF
QUEUE
000A 3F DONE SWI
The 16-bit instructions LDX, LDY, LDU, STX, STY, and STU are very useful
for moving addresses from one place to another. LDX, LDY, and LDU load the index
register or stack pointer with the contents of the effective address and the next sequen-
tial address, thus allowing the loading of a 16-bit address with a single instruction. STX,
STY, and STU similarly store a 16-bit address in memory. The addresses that are loaded
or stored can later be used to fetch individual data items or addresses from a data struc-
ture.
loads Accumulator A from the address that is 20 16 bytes from the start of the block. The
elements in the block may themselves be addresses; for example, the instruction
LDB [$14, X]
.
loads Accumulator B from the address that is stored 14 16 and 15 16 bytes from the start of
the block.
How would we use such data structures? For example, we might want a piece of
test equipment to execute a series of tests as specified by the operator. Using entries
from a control panel, we will make up a queue of blocks of information, one for each test
that the operator will eventually want to run. Each block of information contains:
1. The starting address of the next block (or if there is no next block).
Clearly the block could contain even more information if there were more options
for the operator to specify while setting up the test sequence. Note that some elements
in the block contain data, others contain addresses, while still others may be 1-bit flags.
Note what we mean by flexibility in this example. Some of the procedures that the
operator can easily implement are:
1 Run the same test with different sets of I/O devices. A trial run might use data
from a local keyboard and send the results to the CRT, while a production run
might use data from a remote communications line and produce a permanent
record on a printer.
2. Execute tests in any order, just by changing the order in the queue.
3. Place temporary data in an area where it can easily be displayed or retrieved by
a debugging program.
4. Make alternative decisions as to whether tests should be continued, errors
should be reported, or procedures should be repeated. Here again, trial or
debugging runs may use one option, while production runs use another.
5. Delete or insert tests merely by changing the links which connect a test to its
successor. The operator can thus correct errors or make changes without
reentering the entire list of tests.
For example, assume that the operator enters the sequence TEST 1, TEST 2,
TEST 4, and TEST 5, accidentally omitting TEST 3. The blocks are linked as follows:
Block 1 (for TEST 1) contains the starting address for block 2 (for TEST 2).
Block 2 (for TEST 2) contains the starting address for block 3 (for TEST 4).
Block 3 (for TEST 4) contains the starting address for block 4 (for TEST 5).
Block 4 (for TEST 5) contains a link address of zero to indicate that it is the last
block.
To insert TEST 3 between TEST 2 and TEST 4 merely involves the following
changes.
9-8 6809 Assembly Language Programming
Block 2 (for TEST 2) must now contain the starting address for block 5 (for TEST
3).
Block 5 (for TEST 3) must contain the starting address for block 3 (for TEST 4).
No other changes are necessary and no blocks have to be moved. Note how much
simpler it is to insert or delete using linked lists, rather than lists that are stored in con-
secutive memory locations. There is no problem of moving elements up or down so as to
remove empty spaces.
or create
In our example, the blocks are organized as follows:
If Index Register X contains the starting address of the block, some typical pro-
cedures are:
1. Get a byte of data from the input device and place it in byte 6 of the data
area.
LDA [4,X] GET INPUT DATA
LDY 9,X GET ADDRESS OF DATA AREA
STA 6,Y PLACE INPUT DATA IN DATA AREA
We need indirect addressing here since the block contains the address of the
input device, not the actual input data.
2. Get a byte of data from byte 3 of the data area and send it to the output
device.
LDY 9,X GET ADDRESS OF DATA AREA
LDA 3,Y GET A BYTE OF DATA
STA [6,X] v
SEND DATA TO OUTPUT DEVICE
The indirect addressing allows us to use the address of the output device from
the block. We could move that address to an index register or stack pointer if
we needed it repeatedly.
Queuing can handle lists that are not in sequential memory locations. Each ele-
ment in the queue must contain the address of the next element. Such lists allow the
programmer to handle data or tasks in the proper order, change variables or I/O devices,
or fill in definitions in a program. Queuing requires extra storage as compared to
sequential lists, but elements are far easier to add, delete, or insert.
elements. 4 5 Such doubly linked lists allow you to easily retrace your steps (e.g., repeat
^
the previous task if an error occurs in the current one) or access elements from either
end (e.g., allowing you to remove or change the last two elements without having to go
through the entire queue). The data structure may then be used in either a first-in,
first-out manner manner, depending on whether new ele-
or in a last-in, first-out
ments are added head or to the tail. How would you change the example program
to the
so that memory locations 0044 and 0045 contain the address of the last element (tail) of
the queue?
Empty Queue
If no elements in the queue, the program clears memory locations 0040
there are
and 0041. A
program that requests an element from the queue must check those
memory locations to see if its request has been satisfied (i.e., if there was anything in the
queue). Can you suggest other ways to indicate whether the queue is empty?
Sample Problem:
(0041) = 06 Length of array
proper order.
This sorting method is referred to as a "bubble sort." It is an easy algorithm to
9-10 6809 Assembly Language Programming
The technique operates as follows in a simple case. Let us assume that we want to
sort an array into descending order; the array has four elements — 12, 03, 15, 08.
1st Iteration:
Step 1. INTER - 1
12
15
08
03
since the second pair (03, 15) is exchanged and so is the third pair (03,
08). INTER = 0.
2nd Iteration:
Step 1. INTER = 1
15
12
08
03
since the first pair (12, 15) is exchanged. INTER — 0.
3rd Iteration:
Step 1. INTER - 1
Step 2. The elements are already in order, so no exchanges are necessary and
INTER remains 1.
This approach always requires one extra iteration to ensure that the elements are
in the proper order. No exchanges are performed in the last iteration, so it does not
really accomplish anything. Tracing through the examples shows that many of the
comparisons are wasted and even repetitive. Thus the method could be improved
greatly, particularly if the number of elements is in the thousands or millions, as it
commonly is in large data processing applications. New sorting techniques are an
important area of current research. 9
Program 9-4:
0000 86 01 SORT LDA #1 INTERCHANGE FLAG = 1
0002 97 40 STA $40
0004 96 41 LDA $41 ADJUST ARRAY LENGTH TO NUMBER OF
0006 4A DECA PAIRS
0007 8E 0042 LDX #$42 POINT TO START OF ARRAY
000A E6 80 PASS LDB ,X+ IS. PAIR OF ELEMENTS IN ORDER?
OOOC El 84 CMPB ,x
000E 24 0C BCC COUNT YES, TRY NEXT PAIR
0010 OF 40 CLR $40 NO, CLEAR INTERCHANGE FLAG
0012 34 02 PSHS A SAVE ARRAY COUNTER
0014 A6 84 LDA ,x INTERCHANGE ELEMENTS IF OUT OF
0016 E7 84 STB /X ORDER
0018 A7 IF STA -1,X
001A 35 02 PULS A RESTORE ARRAY COUNTER
001C 4A COUNT DECA
Tables and Lists 9-11
The case where two elements in the array are equal is very important. The pro-
gram should not perform an interchange in that case since that interchange would be
performed in every pass. The result would be that every pass would set the interchange
flag, thus producing an endless loop. The program compares the elements in the
specified order so that the Carry flag is cleared if the elements are already arranged cor-
rectly. Remember that comparing two equal values always clears the Carry flag since the
Carry is a borrow after subtractions or comparisons.
Since the 6809 has a complete set of unsigned conditional branches (BHI, BHS,
BLO, BLS), we could perform the comparison in either direction. The sequence
LDB 1,X IS PAIR OF ELEMENTS IN ORDER?
CMPB ,X+
BLS COUNT
is equivalent to the one in the example program. We must use BLS rather than BLO
(BCS) to force a branch if the elements are equal.
Before starting each sorting pass, we must be careful to reinitialize the index and
the interchange flag.
The program must reduce the counter by 1 initially since the number of consecu-
tive pairs is one less than the number of elements (the last element having no suc-
cessor).
This program does not work properly if there are fewer than two elements in the
array. How could you handle this degenerate case?
Flowchart:
)
Chapter 10 discusses the 6809's Hardware Stack in more detail. Of course, we could
easily substitute a fixed memory location, such as 003F. Note the use of the special
operation codes PSH for Store Registers in Stack and PUL for Load Registers from
Stack, as opposed to the standard ST and LD.
Sample Problem:
(0042) = 02 Index for jump table
(0043) 00)
« Zeroth element in jump table
(0044) C J-
(0045) 00)
in um P ta *" e
(0046) 50 1 First element J
(0047) 00)
Second element in jump table
j-
(0048) 54
(0049) 00)
in jump table
(004A) 58 > Third element
Result: (PC) 0054 since that is entry *2 (starting from zero)
in the jump table. The next instruction to be
executed will be the one located at that address.
Flowchart:
C Start
J
INDEX =
(0042) x 2
JELEM =
BASE + INDEX
(PC) =
(JELEM):
(JELEM + 1
The last box in the flowchart results in a transfer of control to the address obtained
Tables and Lists 9-13
from the table.No ending block is necessary. Such transfers do not bother the processor
at all, but you may want to add special notes to your flowchart and program documenta-
tion so that the sequence does not appear to be a "dead-end street" to the
reader.
Program 9-5:
0000 96 42 LDA $42 GET INDEX
0002 48 ASLA DOUBLE INDEX FOR 2-BYTE ENTRIES
0003 8E 0043 LDX #$43 GET BASE ADDRESS OP JUMP TABLE
0006 6E 96 JMP [A,X] TRANSFER CONTROL TO JUMP TABLE
* ENTRY
When you run program, be sure to place some executable code (such as an
this
SWI instruction) at each address to which control could be transferred. Otherwise the
processor will never get back to the monitor program.
Jump Tables
Jump tables are very useful in situations where the processor must select one of
several routines for execution. Such situations arise in decoding commands (entered,
for example, from a control keyboard), selecting test programs, choosing alternative
methods or units, or selecting an I/O configuration. For example, a 4-position switch
on the front of an instrument or test system may select among the remote, self-test, au-
tomatic, or manual modes of operation. The processor reads the switch and selects the
Address Contents
The jump table replaces a series of conditional jump operations. The program
that accesses the jump table could be used to access several different tables merely by
changing the starting address.
The data must be multiplied by 2 to give the correct index since each entry in the
jump table is a 16-bit address that occupies two bytes of memory. The instruction JMP
[A,X] uses an indirect mode in which the destination is the address stored at the
specified location rather than the location itself. The procedure is as follows:
JMP A,X would actually place the sum of Accumulator A and Index Register X in
JMP is an unconditional jump that allows direct (including base-
the program counter.
page) or indexed addressing, as compared to BRA and LBRA which require relative
addressing.
9-14 6809 Assembly Language Programming
The terminology used in describing jump and branch instructions can be con-
fusing. A jump instruction using direct addressing loads the specified address into
the program counter; the result is more like the outcome of an LDX instruction using
immediate addressing than it is like one using direct addressing. A jump instruction
using one of the indirect modes works like other instructions (such as LDX or STX)
using the corresponding non-indirect mode. For example,
1 JMP $ A000 transfers control to address A000 16 That is, (PC) = A000 16 . .
On the other hand, LDX $A000 loads Index Register X from addresses
A000 16 andA001 16 .Thatis(X) - (A000 16 ):(A001 16 ).
2. JMP ,Y transfers control to the address in Index Register Y. That is, (PC) =
(Y).
On the other hand, LDX ,Y loads Index Register X starting at the address in
Index Register Y. That is, (X) = ((Y)):((Y) + 1).
However, the instruction JMP [,Y] transfers control to the address reached
indirectly through Index Register Y. That is, (PC) = ((Y)):((Y) + 1).
PROBLEMS
9-1. REMOVE ENTRY FROM LIST
Purpose: Remove the byte in memory location 0040 from a list if it is present. The
length of the list is memory location 0041 and the list itself begins in
in
memory location 0042. Move the entries below the one removed up one posi-
tion and reduce the length of the list by 1.
Sample Problems:
(0040) = 6B Entry to be removed from list
(0043) = 61
(0044) = 28
(0045) = 1D
Result: No change. since the entry is not in the list
(0043) = 6B
(0044) = 28
(0045) = 1D
D
The entry is removed from the list and the elements below it are moved up one
position. The length of the list is reduced by 1.
order. Place the new entry in the correct position in the list, adjust the ele-
ments below it down, and increase the length of the list by 1.
Sample Problems:
(0041) = 6B Entry to be added to list
(0044) = 55
(0045) 7D
(0046) A1
Result: (0042) - 05 Length of list increased 1
(0047) A1
(0044) = 55
(0045) 6B
(0046) A1
Result: No change, since the entry is already in the list
the element. The new element goes at the end (tail) of the queue; its address
will be in the element that was at the end of the queue and it will contain zero
to indicate that it is now the end of the queue.
Sample Problem:
(0040) = 00)
._ > New element to be added to queue
(0041)
(0042) 00 \
Pointer to head of queue
(0043)
.
R t
(0046)
_ > Last element in queue
(0047) n
9-16 6809 Assembly Language Programming
Result: (0046) = 00] Old last element points to new last element
(0047) = 4D)
(004D) = 00) New last element in queue
(004E) = 00)
How would you add an element to the queue if memory locations 0044 and 0045
contain the address of the tail of the queue (or last element) ?
Sample Problem:
(0040) = 03 Length of list
(0041) = 191
1 9D 1 First element in list
(0042) = Dlf
(0043) = 3FI
3F60 Second element
(0044) = 60)
(0045) = B5)
=
B52A Third element
(0046) 2AJ
Result: (0041) = B5 )
Largest element
(0042) = 2AJ
(0043) = 3F
(0044) = 60
(0045) = 191
Smallest element
(0046) = Dlf
Sample Problem:
Note: Be sure to place some executable code (such as an SWI instruction) at each
address to which the program could transfer control, so that the processor will get back
to the monitor correctly.
.
REFERENCES
1 J. Hemenway and E. Teja. "EDN Software Tutorial: Hash Coding," EDN, Septem-
ber 20, 1979, pp. 108-10.
2. D. Knuth. The Art of Computer Programming, Volume HI: Searching and Sorting,
Addison-Wesley, Reading, Mass., 1978.
3. D. Knuth. "Algorithms," Scientific American, April 1977, pp. 63-80.
4. K. J. Thurber and P. C. Patton. Data Structures and Computer Architecture, Lex-
ington Books, Lexington, Mass., 1977.
5. J. Hemenway and E. Teja. "Data Structures - Part 1," EDN, March 5, 1979, pp.
89-92. "Data Structures - Part 2," EDN, May 5, 1979, pp. 113-16.
6. See Reference 2.
The following chapters will discuss more advanced areas of assembly language
programming. Chapters 10 and 11 deal with subroutines, an important aspect of all
levels of programming. Chapter 10 defines and gives examples of subroutines, while
Chapter 1 1 discusses 6809 implementations of important parameter passing techniques.
The following three chapters cover input and output, a microprocessor's contact with
the outside world. In Chapter 12 we discuss time delays and different types of periph-
erals.Chapter 13 deals with the 6820 Peripheral Interface Adapter, a popular parallel
I/O device for Motorola processors, and gives examples of basic program tasks for that
device. Chapter 14 illustrates basic routines for a serial interface device, the 6850
Asynchronous Communications Interface Adapter. Chapter 15 treats the important and
often confusing topic of interrupts.
10
Subroutines
None of the examples that we have shown so far is typically a program all by
itself. Most real programs perform a series of tasks, many of which may be the same
or may be common to several different programs. We need a way to formulate these
tasks once and make the formulations conveniently available both in different parts
of the current program and in other programs.
Subroutine Library
The standard method is to write subroutines that perform particular tasks. The
resulting sequences of instructions can be written once, tested once, and then used
repeatedly. They can form a subroutine library that provides documented solutions to
common problems.
Subroutine Instructions
Most microprocessors have special instructions for transferring control to
subroutines and restoring control to the main program. We often refer to the special
instruction that transfers control to a subroutine as Call, Jump-to-Subroutine, Jump and
Mark Place, or Jump and Link. The special instruction that restores control to the main
program usually called Return.
is
the Stack and puts it back in the Program Counter. The effect is to transfer program
control, first to the subroutine and then back to the main program. Clearly the
subroutine may itself transfer control to a subroutine, and so on.
Parameters
In order to be really useful, a subroutine must be general. A routine that can per-
form only a specialized task, such as looking for a particular letter in an input string of
fixed length, will not be very useful. If, on the other hand, the subroutine can look for
any letter in strings of any length, it will be far more helpful. We call the data or
addresses that the subroutine allows to vary "parameters." An important part of writ-
ing subroutines is deciding which variables should be parameters.
One problem is transferring the parameters to the subroutine; this process is
called passing parameters. The simplest method is for the main program to place the
parameters into registers. Then the subroutine can simply assume that the
parameters are there. Of course, this technique is limited by the number of registers
available. The parameters may, however, be addresses as well as data. For example, a
sorting routine could begin with Index Register X containing the starting address of the
array. Such 6809 features as indirect addressing, indexed addressing using the Stack
Pointers, the ability to push and pop entire sets of registers with one instruction, the
availability of both the user and the Hardware Stack Pointer, and the LEA instruction
provide far more powerful and more general ways of passing parameters. The main
program can place the parameters in the Stack and the subroutine can easily access
them, utilize the Stack for temporary storage, and place the results back in the Stack.
The only problems are keeping track of the return address (and not changing it) and
cleaning the Stack of unwanted data. The two stack pointers and the LEA instruction are
particularly helpful in stack management, as we shall show in Chapter 1 1. In that chapter
we will also describe more general approaches to passing parameters.
Types of Subroutines
Sometimes a subroutine must have special characteristics. A subroutine is
relocatable if it can be placed anywhere in memory. You can use such a subroutine
Subroutine Documentation
Most programs consist of a main program and several subroutines. This is
advantageous because you can use proven routines and debug and test the other
subroutines separately. You must, however, be careful to use the subroutines pro-
perly and remember their exact effects on registers and memory locations.
Subroutine listings must provide enough information so that users need not
examine the subroutine's internal structure. Among the necessary specifications are:
Hardware Stack
The following examples all reserve an area of memory for the hardware stack.
We have arbitrarily started the hardware stack at address OOFF by initializing the
Stack Pointer to 0100 16 If your microcomputer establishes a Stack area, you may use it
.
instead and you will not need an initial LDS instruction. If you wish to establish your
own stack area, remember to save and restore the monitor's Stack Pointer (in two
specified RAM locations) in order to produce a proper return at the end of your main
program.
PROGRAM EXAMPLES
10-1. CONVERTING HEXADECIMAL TO ASCII
Purpose: Convert the contents of Accumulator A from a hexadecimal digit to an ASCII
character. Assume that the original contents of Accumulator A are a valid
hexadecimal digit.
Sample Problems:
(A) = OC
Result: (A) » A3 C
(A) = 06
Result: (A) = 36 '6
10-4 6809 Assembly Language Programming
Flowchart:
Program 10-1:
The calling program starts the Stack at memory location OOFF, gets the data from
memory location 0040, calls the conversion subroutine, and stores the result in memory
location 0041.
Subroutine Documentation:
SUBROUTINE ASDEC
*
PURPOSE: ASDEC CONVERTS A HEXADECIMAL
DIGIT IN ACCUMULATOR A TO AN
ASCII DIGIT IN ACCUMULATOR A
*
INITIAL CONDITIONS: HEXADECIMAL DIGIT IN A
*
FINAL CONDITIONS: ASCII CHARACTER IN A
*
REGISTERS AFFECTED: A, FLAGS
*
SAMPLE CASE
INITIAL CONDITIONS: 6 IN ACCUMULATOR A
FINAL CONDITIONS: ASCII 6 (HEX 35)
IN ACCUMULATOR A
Subroutines 10-5
The 6809 Stack grows downward (toward lower addresses); the Stack Pointer
always contains the address of the last occupied location, rather than the next empty
one as on some other microprocessors (including the 6800 and 6502). This means you
must initialize the Stack Pointer to a value one higher than the largest address in the
Stack area (e.g., initializing the Stack Pointer to 0100 16 means that the largest address in
the Stack area will be 00FF 16 ).
JSR Instruction
The 6809 always decrements the Stack Pointer before storing a byte of data, so the
procedure is the same as in the autodecrement addressing mode. Although the pro-
cessor stores the LSB's of the current program counter first, the address ends up in the
usual 6809 form (MSB's at the lower address) since the Stack is growing down (toward
lower addresses).
The overall effect of JSR is:
«S)-1) — (PCL)
US)-2) — (PCH)
(S) — (S) - 2
(PC) — EA
where PCH and PCL are the most and least significant bytes of the Program Counter,
respectively, S is the Hardware Stack Pointer, and EA is the effective address for the
JSR instruction. Since the processor has fetched the entire JSR instruction, the program
counter contains the address of the following byte.
In our example, the effect of JSR ASDEC is:
(OOFF) — 09 »
V Return address
(OOFE) — OO >
(S) — OOFE
(PC) — 0020
The only difference between JSR and JMP is that JSR "remembers" where it
came from, thus providing for the resumption of the main program. The processor
keeps a record in the hardware stack, much as one might jot down a starting point on a
piece of paper. The advantages of using the stack are that it is ordered and expanda-
ble; subroutines can themselves call subroutines and so on without destroying any of
the return addresses or restoring them in the wrong order. The latest return address is
always at the top of the hardware stack, with the others under it in the order in which
they will be used.
10-6 6809 Assembly Language Programming
RTS Instruction
The Return from Subroutine (RTS) instruction retrieves the return address
from the Stack (loading the top two bytes) and places that address back in the Pro-
gram Counter. The procedure is:
STEP 1 — Load top byte from the stack into the MSB's of
the Program Counter, increment Stack Pointer.
STEP 2 — Load top byte from the stack into the LSB's
of the Program Counter, increment Stack Pointer.
The 6809 microprocessor always increments the Stack Pointer after loading a byte
of data, so the procedure is the same as in the autoincrement addressing mode. RTS bal-
ances JSR, much as a right parenthesis balances a left parenthesis. The actions of RTS,
however, are automatic; it simply takes the top two bytes in the hardware stack and
places them in the Program Counter. The programmer must ensure that those top two
bytes contain a legitimate return address; the processor does not examine them.
The overall effect of RTS is:
(PCH) - (IS))
(PCD — (IS) + 1)
<S) — (S) + 2
the address ASCZ is relative. The use of BSR (Branch-to-Subroutine) rather than JSR
would make the calling program relocatable as well.
The Jump-to-Subroutine instruction results in the execution of four or five
instructions, taking 12 or 14 clock cycles. A subroutine call may take a long time even
though it appears to be a single instruction in the program. Calling a subroutine always
involves some overhead as well, since both the Jump-to-Subroutine and the Return-
from-Subroutine instructions take time. In fact, a JSR takes 4 clock cycles longer than
the corresponding JMP (with the same addressing mode) because JSR must save the
current Program Counter in the RAM
stack; RTS always takes 5 clock cycles.
If you use the stack for passing parameters, remember that Jump or Branch to
Subroutine always saves the return address at the top of the stack. You can refer to the
parameters using indexed addressing with offsets of 2 or more from the Hardware Stack
Pointer (the return address occupies the addresses with offsets and 1).
Subroutines 10-7
Sample Problems:
(X) = 0043 Starting address of string
(0043) = 52 R'
(0044) = 41 'A'
(0045) = 54 *T
(0046) as 48 'H'
(0047) = 45 'E'
(0048) = 52 'R'
(0049) = OD CR
Result: (B) = 06
Flowchart:
c Start
POINTER = (X)
COUNT =
COUNT =
COUNT + 1
POINTER =
POINTER + 1
Program 10-2:
The calling program starts the Stack at memory location OOFF, gets the starting
address of the string from memory locations 0040 and 0041, calls the string length
subroutine, and stores the result in memory location 0042.
The subroutine determines the length of the string of ASCII characters and places
the length in Accumulator B.
Subroutine Documentation:
SUBROUTINE STLEN
*
PURPOSE: STLEN DETERMINES THE LENGTH
* OF A STRING (NUMBER OF CHARACTERS
* BEFORE A CARRIAGE RETURN)
*
INITIAL CONDITIONS: STARTING ADDRESS
* OF STRING IN INDEX REGISTER X
*
FINAL CONDITIONS: NUMBER OF CHARACTERS IN B
*
REGISTERS AFFECTED: A,B,X,FLAGS
*
SAMPLE CASE
INITIAL CONDITIONS: (X) = 0042
(0042) = 4D, (0043)= 41, (0044) = 4E, (0045) = OD
FINAL CONDITIONS: (B) = 03
Sample Problem:
(B) = 05 Length of array (number of bytes)
(X) = 00' Starting address of array
(0043) = 67
(0044) = 79
(0045) = 15
(0046) = E3
(0047) = 72
Result: (A) E3, since this is the largest of the five unsigned
numbers in the array
Flowchart:
Start
COUNT = (B)
POINTER = (X)
MAX =
MAX = (POINTER)
POINTER =
POINTER +
H 1
COUNT =
COUNT - 1
10-10 6809 Assembly Language Programming
Program 10-3:
The calling program starts the Stack at memory location OOFF, sets the starting
address of the array to 0043, gets the length of the array from memory location 0040,
calls the maximum subroutine, and stores the maximum value in memory location
0041.
0000 ORG $0000
0000 10CE 0100 : LDS #$0100 START STACK AT MEMORY LOCATION
* OOFF
0004 8E 0043 LDX #$43 GET STARTING ADDRESS OF ARRAY
0007 D6 40 LDB $40 GET LENGTH OF ARRAY
0009 BD 0020 JSR MAXM FIND MAXIMUM VALUE
000C 97 41 STA $41 SAVE MAXIMUM VALUE IN MEMORY
000E 3F SWI
Subroutine Documentation:
SUBROUTINE MAXM
*
PURPOSE: MAXM DETERMINES THE MAXIMUM VALUE IN AN ARRAY OF 1
Sample Problems:
a. (B) = 03 Length of strings
(X) = 0046 Starting address of string #1
(Y) = 0050 Starting address of string #2
(0046) » 43 C
(0047) = 41 'A'
(0048) » 54 T
(0050) » 43 C
(0051) = 41 'A'
(0052) 54 T
Result: (B) 00 since the strings are the same
(0047) 41 'A'
(0048) 54 •V
(0050) 43 c
(0051) 41 'A'
(0052) 54 T
Result: (B) = FF since the first characters differ
Program 10-4:
The calling program memory location OOFF, sets the two start-
starts the Stack at
ing addresses (Index Registers X and
0046 and 0050 respectively, gets the length
Y) to
of the string from memory location 0041, calls the pattern match subroutine, and places
the result in memory location 0040.
Flowchart:
c Start
)
POINTER 1 = (X)
POINTER2 = (Y)
COUNT = (B)
POINTER 1 =
POINTER 1 + 1
POINTER2 =
POINTER2 + 1
COUNT= COUNT -1
MARK = FF 16
Subroutine Documentation:
SUBROUTINE PMTCH
*PURPOSE: PMTCH DETERMINES IF TWO STRINGS ARE IDENTICAL
*
INITIAL CONDITIONS: STARTING ADDRESSES OF STRINGS IN INDEX
REGISTERS X AND Y, LENGTH OF STRINGS (IN BYTES) IN
ACCUMULATOR B
*
FINAL CONDITIONS: ZERO IN ACCUMULATOR B IF STRINGS MATCH,
FF IN ACCUMULATOR B OTHERWISE
*
REGISTERS AFFECTED: A,B,X,Y, FLAGS
*
SAMPLE CASE:
INITIAL CONDITIONS: (X) = 0046, (Y) = 0050, (B) = 02
(0046) = 36, (0047) = 39
(0050) = 36, (0051) = 39
RESULT: ( B) =00 SINCE THE STRINGS ARE IDENTICAL
This subroutine, like the preceding examples, changes all the flags. You should
generally assume that a subroutine call changes the flags unless it is specifically stated
otherwise. If the main program needs the old flag values (for later checking) it must ,
save them in the Stack (using PSHS CC) before calling the subroutine, and restore them
afterward (using PULS CC).
Subroutines 10-13
This subroutine has three parameters — two starting addresses and the length of
the strings. Two index registers (X and Y) are used for the starting addresses;
Accumulator B is used for both the length of the strings and for the result. The
subroutine changes Accumulator A incidentally.
The subroutine is reentrant, since it uses no fixed addresses.
Obviously, subroutines become far more complicated as soon as the number of
parameters exceeds the number of registers. Using the registers is convenient, but it
lacks generality; as soon as the number of parameters becomes large, you must use an
entirely different approach.
Note that the subroutine has two exit points (i.e., two RTS instructions). This cre-
ates no problems, since either RTS terminates the subroutine and transfers control back
to the main program.
Sample Problem:
(B) Length of numbers in bytes
<X) Starting address of first number
(Y) Starting address of second number
(U) Starting address of result
(0048)
(0049) number
2F5BA7C3 ^ 6 is first
(004A)
(004B)
(004C)
(004D)
1 4DF35B8 is second number
(004E) 1
(004F)
Result: (0050)
(0051)
443ADD7B 16 issum
(0052)
(0053)
Program 10-5:
The calling program starts the Stack at memory location OOFF, sets the starting
addresses of the various numbers to 0048, 004C, and 0050, respectively, gets the length
of the numbers (in bytes) from memory location 0040, and calls the multiple-precision
addition subroutine.
Flowchart:
c Start
POINTER 1 = (X)
POINTER2 = (Y)
POINTER3 = (U)
COUNT = (B)
CARRY =
(POINTER3) =
(POINTER 1) +
This step also produces a new carry.
(POINTER2) +
CARRY
POINTER 1 =
POINTER1 + 1
POINTER2 =
POINTER2 + 1
POINTER3 =
POINTER3 + 1
COUNT = COUNT
- 1
Subroutine Documentation:
SUBROUTINE MPADD
PURPOSE: MPADD ADDS TWO MULTI-BYTE BINARY NUMBERS
INITIAL CONDITIONS: STARTING ADDRESSES OF NUMBERS (LSB'S) IN
* INDEX REGISTERS X AND Y, STARTING ADDRESS OF SUM IN USER
STACK POINTER U, LENGTH OF NUMBERS (IN BYTES) IN ACCUMULATOR B
*
REGISTERS AFFECTED: A, B , X, Y, U, FLAGS
*
SAMPLE CASE:
INITIAL CONDITIONS: (X) = 0048, (Y) = 004C, (U) = 0050,
(B) = 02, (0043) = C3, (0049) = A7, (004C) = B8 , (004D) = 35
RESULT: (0050) = 7B, (0051) = DD
*
This subroutine has four parameters — three addresses and the length of the
numbers. We use Index Register X, Index Register Y, User Stack Pointer U, and
Accumulator B to pass them; no results are returned. User Stack Pointer U is really just
Subroutines 10-15
an extra index register. It is, in fact, somewhat more useful than Index Register Y since
LDU and STU execute faster than LDY and STY. The reason for this difference is that
LDU and STU require 1-byte operation codes, while LDY and STY require 2-byte
operation codes. Note, however, that CMPU requires a 2-byte operation code, so U ts
slightly inferior to X. A further advantage of U which we will discuss shortly is the
availability of the PSHU and PULU instructions, which can transfer an entire set of
registers to or from the User Stack.
POSITION-INDEPENDENT CODE
Position-independent routines can be placed anywhere in memory without
using a relocating loader and can be used with any combination of other programs.
The keys to writing position-independent code are:
1. Use relative branches (BSR, LBSR, BRA, LBRA), rather than JSR or JMP.
2. Refer to variables by means of the indexed addressing modes that use a
constant offset from the Program Counter. Remember that the assembler
will calculate a relative offset for you if you specify the address as DEST, PCR.
Thus the instruction
LDA RDATA, PCR
will load Accumulator A from the relative address RDATA. You can use the
indirect version to access data through addresses that are stored relatively.
3. Use the Hardware Stack for temporary storage. You can assign five Stack
locations for temporary storage by subtracting five from the Hardware Stack
Pointer with the instruction
LEAS -5,S
You can then refer to these locations with indexed offsets and finally discard
them with the instruction
LEAS 5,S
Note that such temporary storage locations are only allocated when the routine is
which saves its absolute value (the address of the byte following the TFR instruction) in
Index Register X. The program can thereby calculate its actual location in memory.
10-16 6809 Assembly Language Programming
NESTED SUBROUTINES
The BSR and JSR instructions allow the nesting of subroutines, since subse-
quent subroutine calls will place their return addresses on top of the previous return
addresses. No addresses are ever lost and an RTS instruction always returns control to
the instruction just after the most recent BSR or JSR.
We can use other methods to call one level of subroutine. For example, the
instruction
EXG X,PC
loads the Program Counter with the previous contents of Index Register X and Index
Register X with the previous contents of the Program Counter. This is equivalent to
transferring control to the address in Index Register X, while saving the return address
in that index register. However, this approach does not allow nesting, since Index
RegisterX can only hold a single return address. Furthermore, ties up Index Register
it
X and makes the program rather difficult to follow. If you use this approach, remember
that the instruction
EXG X,PC
at theend of the subroutine will transfer control back to the main program (as long as
you have not disturbed Index Register X) and will save the address immediately follow-
ing the EXG instruction in Index Register X. This approach is often referred to as
jump-and-link, since it uses Index Register X as the link back to the main program.
PROBLEMS
Note that you are to write both a calling program for the sample problem and a
properly documented subroutine.
Sample Problems:
a. (A) = 43 'C
Result: (A) = OC
b. (A) = 36 '6'
Result: (A) = 06
Subroutines 10-17
Sample Problem:
(X) 0044 Starting address of string
(0044) 49
(0045) 02 STX
(0046) 47 'G'
'0'
(0047) 4F
(0048) 03 ETX
Result: (B) 02 since there are 2 characters between the ASCII
STX and the ASCII ETX.
Sample Problem:
(B) = 05 Length of array (number of bytes)
(X) = 00 Starting address of array
(0043) = 67
(0044) = 79
(0045) = 15
(0046) = E3
(0047) = 73
Result: (A) 1 5 since this is the smallest of the five
unsigned numbers.
Sample Problems:
(B) 03 Length of strings
(X) 0046 Starting address of string #1
(Y) 004A Starting address of string #2
(0046) 43 'C
(0047) 41 'A'
(0048) 54 T
(004A) 42
(004B) 41
(004C) 54
Result: (B) = 00 since CAT is "larger" than BAT.
10-18 6809 Assembly Language Programming
(004A) - 44 'C
(0048) =41 'A'
(004C) = 54 T
Result: (B) = 00 since the two strings are the same
(004A) = 43 'C
(004B) = 55 'U'
(004C) = 54 T
Result: (B) = FF since CUT is "larger" than CAT
is positive, FF if it is negative.
Sample Problem:
(0048)
(0049)
36701985 is minuend
(004A)
(004B)
(004O
(004D) 1 2663459 is subtrahend
(004E)
(004F)
(0050)
(0051)
24038526 is decimal difference
(0052)
(0053)
11
Parameter Passing Techniques
-Pull Order
7 6 5 4 3 2 1 * -Bit Number
I PC U Y X DP B A eel
S
Push Order
Bit position 6 represents U for PULS and PSHS, S for PULU and PSHU.
Figure 11-1. Assignment of Bits and Orders for PSH and PUL Instructions
The Stack grows downward, so the first registers pushed will end up at the
highest addresses and the first registers pulled will come from the lowest addresses.
16-bit registers are pushed least significant byte first and pulled most significant
byte first, thus maintaining compatibility with the standard 6809 method for storing 16-
bit addresses or data. The 6809's Stack Pointers are decremented before each byte is
7 SP— SP - 2
STACK—PC
Last byte pushed CC ppqq -12=
6 SP— SP - 2
STACK— U or S A final SP contents
5 SP— SP - 2 B
STACK— DP
4 SP— SP - 2 XH
STACK—
XL
3 SP— SP - 1
STACK— DP YH
2 SP— SP - 1 YL
STACK— UH or SH
1 SP— SP - 1
UL or SL
STACK—
PCH
SP— SP - 1
SP represents either the Hardware Stack Pointer (PSHS) or the User Stack Pointer
(PSHU). Either PSH instruction can save any, all, any subset, or none of the user
registers except its own pointer. The assembly language programmer simply provides a
list of registers (in any order) in the operand field. The order in which registers
are saved
is a function of the hardware, not of the order in which the programmer specifies them.
Parameter Passing Techniques 11-3
The PULS or PULU instruction pulls the registers from the stack in the following
order:
l
SP— SP + 1
First byte pulled CC ppqq =
A— STACK initial SP contents
SP— SP + 1
A
2 B— STACK B
SP— SP + 1
DP
3 DP— STACK XH
SP— SP + 1
XL
4 X— STACK
SP— SP + 2 YH
5 Y— STACK YL
SP— SP + 2 UH or SH
6 U or S— STACK UL or SL
SP— SP + 2
PCH
7 PC— STACK
SP— SP + 2 Last byte pulled PCL
ppqq +12 =
final SP contents
PSH and PUL are particularly convenient when the entire state of a task must be
saved or restored because the task has been suspended, preempted, or newly activated.
1.2
GENERAL PARAMETER PASSING TECHNIQUES
The registers often provide a fast, convenient way of passing parameters to
subroutines and returning results. The limitations of this method are that it cannot be
expanded beyond the number of registers, it often results in unforeseen side effects, and
it The tradeoff here is between fast execution time and a more general
lacks generality.
approach. Such a tradeoff is common in computer applications at all levels; general
approaches are easy to learn, consistent, and can be automated through the use of
compilers and other systems programs. On the other hand, approaches that take
advantage of the specific features of a particular task require less time and memory.
The choice of one approach or the other depends on your application, but you should
take the general approach (saving programming time and simplifying documentation
and maintenance) unless time or memory constraints force you to do otherwise.
There are two general approaches to passing parameters:
1. Place the parameters (or arguments) immediately after the subroutine call.
The approach is convenient when the parameters are constants for a par-
first
ticular subroutine call, while the second approach is more general and is usually the
choice made in writing interpreters, compilers, operating systems, and other systems
programs.
11-4 6809 Assembly Language Programming
to execute from ROM, although the constants may be the addresses of variable data or
arrays. The programmer must implement this approach as follows:
1. Use the DATA directives to store the parameters in program memory. For
the 6809 assembler, the directives are FCB for byte-length data, FDB for 16-
bit data or addresses, and FCC for character data.
2. Access the data by means of the return address that the JSR or BSR instruc-
tion stores at the top of the Hardware Stack. The return address will actually
be the starting address of the list of parameters. You can access the first ele-
LDA [,S]
or you can load the starting address into an Index Register (U, for example)
with an instruction like
LEAU [,S]
3. Adjust the return address so that it points to the next executable instruc-
tion.That is, add the length of the parameter list to the actual return address
so that the processor does not accidentally try to execute the subroutine
parameters. If the return address is in the User Stack Pointer U and the
parameters occupy 5 bytes of program memory, the sequence
LEAU 5,U MOVE RETURN ADDRESS PAST PARAMETERS
STU ,S SAVE ADJUSTED RETURN ADDRESS IN STACK
RTS
will return control to the next executable instruction.
EXAMPLES
11 -1a. LENGTH OF A STRING OF CHARACTERS
Purpose: Determine the length of a string of ASCII characters. The terminating
character and the starting address of the string follow the subroutine call. The
length of the string (excluding the terminating character) is returned in
Accumulator B. No other registers are affected.
Sample Problems:
a. The subroutine call is followed by:
FCB $0D TERMINATIN
FDB $43 STARTING A
(0043) » 52 'R'
(0044) = 41 'A'
(0045) = 54 -T
(0046) 48 'H'
(0047) = 45 'E'
(0048) = 52 'R'
(0049) = OD CR
Result: (B) - 06
Parameter Passing Techniques 11-5
(0043) = OD CR
Result: (B) = 00
Program 11 -1a:
The calling program starts the Stack at memory location OOFF, calls the string
length subroutine (specifying the terminator and starting address in the next three
bytes), and stores the result in memory location 0042.
Subroutine Documentation:
SUBROUTINE STLEN
*
PURPOSE: STLEN DETERMINES THE LENGTH OF A STRING (NUMBER OF
* CHARACTERS PRECEDING A TERMINATOR)
*
INITIAL CONDITIONS: TERMINATOR IN BYTE IMMEDIATELY FOLLOWING
* SUBROUTINE CALL, STARTING ADDRESS OF STRING IN NEXT TWO
* BYTES (MSB'S IN FIRST BYTE)
*
FINAL CONDITIONS: NUMBER OF CHARACTERS IN B
*
REGISTERS AFFECTED: B
SAMPLE CASE:
INITIAL CONDITIONS TERMINATOR = OD, STARTING ADDRESS 0042
(0042) = 4D, (0043) = 41, (0044) 4E, (0045) = OD
FINAL CONDITIONS: ( B) = 03
TYPICAL CALL:
JSR STLEN
FCB TERM TERMINATOR
FDB START STARTING ADDRESS OF STRING
The parameters follow the subroutine call in memory. We are mixing instructions
and assembler directives, a practice that is acceptable as long as the processor never acci-
dentally executes anything that is not an instruction. The result of the JSR instruction is:
11-6 6809 Assembly Language Programming
The subroutine begins by storing all the incidental registers that it uses in the
Stack with PSHS. The result is:
((S)-1) = (OOFD)— (UL)
«S)-2) = (OOFC)- (UH)
((S)-3) = (OOFB)— (XL)
((S)-4) = (OOFA)— (XH)
((S)-5) = (00F9)-(A)
((S)-6) = (00F8)— (CC)
(S)— (S) - 6 = OOFE - 6 = 00F8
Now the instruction LDU 6,S loads the return address from memory locations
OOFE and OOFF into the User Stack Pointer.
The instruction PULU A,X loads the parameters into Accumulator A (the ter-
minating character) and Index Register X. Note that the order of the parameters is criti-
After the length of the string has been determined in the same way as before, the
instruction STU 6,S saves the adjusted return address in the Hardware Stack.
((S) + 6) = (00F8 + 6) = (OOFE)— (UH) = 00
((S) + 7) = (00F8 + 7) = (OOFF)— (UL) = OA
Finally PULS PC,X,U,A,CC restores all the registers and transfers control back to
the main program. No RTS instruction is necessary.
(CC)-((S)) = (00F8)
(A)- ((S)+1> = (00F9)
(XH)— ((S)+2) = (OOFA)
(XL)— US) +3) = (OOFB)
(UH)— ((S)+4) = (OOFC)
(UD— ((S)+5) - (OOFD)
(PCH)— US) +6) = (OOFE) = 00
(PCU— ((S)+7) = (OOFF) = OA
(S)— (S) + 8 = 00F8 + 8 » 0100
Obviously the programming here is a great deal more complex and harder to
understand than in the earlier version, Program 10-2. However, this version is
reentrant, general, has no incidental side effects, and allows simple variation of the
starting address and terminating character in different calls. Other parameters that we
could add easily include a limiting number of characters (the maximum number that the
routine will examine), an error exit (in the event that the processor does not find a ter-
minating character), a starting character, and a memory address in which to store the
result. You might try to expand the routine in a general way to include some or all of
these parameters.
Parameter Passing Techniques 11-7
Sample Problem:
(0048) = C3
(0049) = A7
2F5BA7C3 16 is first number
(004A) = 5B
(004B) = 2F
(004C) = B8
(004D) = 35 14DF35B8 16 is second number
(004E) = DF
(004F) = 14
Result: (0050) = 7B
(0051) = DD
(0052) = 3A 443ADD7B 16 issum
(0053) = 44
Program 11 -2a:
The calling program starts the Stack at memory location OOFF and calls the multi-
ple-precision addition subroutine, specifying the length (in bytes) and the starting
Subroutine Documentation:
*SUBROUTINE MPADD
*
PURPOSE: MPADD ADDS TWO MULTI-BYTE BINARY NUMBERS
*
INITIAL CONDITIONS: SUBROUTINE CALL IS FOLLOWED BY LENGTH OF
STRINGS (IN BYTES), STARTING ADDRESSES OF LSB'S OF OPERANDS,
AND STARTING ADDRESS OF LSB'S OF SUM
*
REGISTERS AFFECTED: NONE
*
SAMPLE CASE:
INITIAL CONDITIONS: LENGTH = 02, OPERAND ADDRESSES = 0048 AND
004C,
ADDRESS OF SUM = 0050
(0048) = C3, (0049) = A7, (004C) = B8, (004D) = 35
RESULT: (0050) = 7B, (0051) = DD (A7C3 + 35B8 = DD7B)
*
TYPICAL CALL:
JSR MPADD
FCB LNGTH LENGTH OF STRINGS (IN BYTES)
FDB OPER1 STARTING ADDRESS (LSB'S) OF OPERAND 1
FDB OPER2 STARTING ADDRESS (LSB'S) OF OPERAND 2
FDB SUM STARTING ADDRESS (LSB'S) OF SUM
The only new problem here is that we cannot pull U from its own stack and we are
very reluctant to change S (since used automatically in interrupts as we shall see in
it is
Chapter 15). So we must tiptoe around this limitation, retaining reentrancy as follows:
1. PULU X,Y,B loads the length of the numbers into Accumulator B and the
starting addresses of the operands into Index Registers X and Y, respectively.
2. LDU ,U loads the starting address of the result into the User Stack Pointer U.
3. The ending sequence
LDU 9 , S
LEAU 7,U
STU 9,S
adds 7 to the return address stored in the Stack, so that it now points to the
address immediately following the list of arguments.
Sample Problems:
a. The subroutine call occurs with the top of the Hardware Stack containing:
OD String terminator
00 MSBs of starting address of string
43 LSBs of starting address of string
empty byte "Hole" for length of string
(0043) = 52 'R'
(0044) = 41 'A'
(0045) = 54 T
(0046) = 48 'H'
(0047) = 45 'E'
(0048) = 52 'R'
(0049) - OD CR
e top of the Hardware S
OD String terminator
00 MSBs of starting address of string
43 LSBs of starting address of string
06 Length of string (in bytes)
b. The subroutine call occurs with the top of the Hardware Stack containing:
OD String terminator
00 MSBs of starting address of string
43 LSBs of starting address of string
empty byte "Hole" for length of string
(0043) = OD CR
Result: The top of the Hardware Stack contains:
OD String terminator
00 MSBs of starting address of string
43 LSBs of starting address of string
00 Length of string (in bytes)
Program 11 -1b:
The calling program starts the stack at memory location OOFF, leaves an empty
byte on the stack for the string length, stores the terminator and starting address on the
removes the parameters from the stack (by
stack, calls the string length subroutine,
incrementing the Hardware Stack Pointer), loads the string length from the stack, and
stores the string length in memory location 0042.
Subroutine Documentation:
SUBROUTINE STLEN
*
PURPOSE: STLEN DETERMINES THE LENGTH OF A STRING (NUMBER OF
* CHARACTERS PRECEDING A TERMINATOR)
*
INITIAL CONDITIONS: TERMINATOR ON TOP OF STACK, FOLLOWED BY
* STARTING ADDRESS OF STRING AND AN EMPTY BYTE FOR THE STRING
* LENGTH
*
* FINAL CONDITIONS: STRING LENGTH ON STACK UNDER PARAMETERS
*
REGISTERS AFFECTED: NONE
SAMPLE CASE:
INITIAL CONDITIONS: TERMINATOR = OD, STARTING ADDRESS =
(0042) = 4D, (0043) = 41, (0044) = 4E, (0045) = OD
FINAL CONDITIONS: STRING LENGTH 03
TYPICAL CALL:
LEAS -1,S LEAVE EMPTY BYTE FOR LENGTH OF STRING
LDA #TERM STRING TERMINATOR
LDX #START STARTING ADDRESS OF STRING
PSHS A,X SAVE PARAMETERS IN STACK
JSR STLEN DETERMINE STRING LENGTH
Here the idea is to leave space for the results on the stack, store the parameters on
top of that space, the subroutine, save the registers, use the parameters to calculate
call
the results, save the results on the Stack, restore the registers, return to the main pro-
gram, clear the parameters from the stack by increasing the Stack Pointer, and remove
the results from the top of the stack.
LEAS — 1 ,S leaves one location in the Stack for the length of the string. The result
1S "
(S)— (S) - 1 = 0100 - 1 = OOFF
The processor does not store anything in the extra stack location.
PSHS A,X stores the parameters in the Hardware Stack. The result is:
JSR STLEN transfers control to the subroutine and saves the return address
(0010) at the top of the Stack. The result is:
LEAU 9,S loads the User Stack Pointer with the starting address of the list of
parameters.
(U)— (S) + 9 = 00F3 + 9 = OOFC
PULU A,X loads the parameters into Accumulator A (the terminating character)
and Index Register X (the starting address of the string).
(A)-((U)) = (OOFC) = OD
(XH)— ((10+1) = (OOFD) = 00
(XL)-((U)+2) = (OOFE) = 43
(U)— (U) + 3 = OOFC + 3 = OOFF
STB ,U stores the length of the string in the "hole" in the stack.
PULS PC,X,U,B,A,CC restores all the incidental registers and transfers control
back to the main program.
(CO— ((S) = (00F3)
(A)— ((S) + 1) = (00F4)
(B)-((S)+2) = (00F5)
(XH)— «S)+3) = (OOF6)
(XL)-((S)+4) = (OOF7)
(UH)— ((S)+5) = (OOF8)
(UU— ((S)+6) = (OOF9)
(PCH>— US)+7) = (OOFA) = 00
(PCD— ((S)+8) = (OOFB) = 10
(S)— (S)+9 = 00F3 + 9 = OOFC
Back in the main program, LEAS 3,S cleans the stack, essentially removing all the
parameters.
(S)— (S)+3 = OOFC + 3 = OOFF
Finally PULS A removes the result (the length of the string) from the Hardware
Stack.
(A)-((S)) = (OOFF)
(S)— (S)+1 = OOFF + 1 = 0100
Here again the programming is more complex and harder to understand than in
our initial simple version, but this version is no incidental
also reentrant, general, has
side effects, and allows simple variation of parameters and generalization.
11-12 6809 Assembly Language Programming
Sample Problem:
The subroutine call occurs with the top of the Hardware Stack containing:
(0048) ss C3
(0049) = A7 2F5BA7C3 16 is first number
(004A) = 5B
(004B) = 2F
(004C) = B8
(004D) = 35 1 4DF35B8 16 is second number
(004E) = DF
(004F) = 14
Result: (0050) = 78
(0051) = DD 443ADD7B, 16 issum
(0052) = 3A
(0053) = 44
Program 11 -2b:
The calling program starts the stack at memory location OOFF, stores the starting
addresses of the strings and the length in the stack, calls the multiple-precision addition
subroutine, removes the parameters from the stack (by increasing the Hardware Stack
Pointer), loads the starting address of the sum from the stack, and stores the starting
address in memory locations 0040 and 0041.
Subroutine Documentation:
SUBROUTINE MPADD
TYPICAL CALL:
LDX #0PER1 STARTING ADDRESS (LSB'S) OF OPERAND
LDY #OPER2 STARTING ADDRESS (LSB'S) OF OPERAND
LDU #SUM STARTING ADDRESS (LSB'S) OF SUM
LDA #LENGTH LENGTH OF STRINGS (IN BYTES)
PSHS U,Y,X,A SAVE PARAMETERS IN HARDWARE STACK
JSR MPADD PERFORM MULTIPLE-PRECISION ADDITION
TYPES OF PARAMETERS
Regardless of our approach to passing parameters, we can specify the
parameters in a variety of ways. For example, we can:
1. Place the actual values in the parameter list. We can use immediate
addressing or DATA
directives and retrieve the data, if necessary, by using
indexed This method is sometimes referred to as call-by-value, since
offsets.
only the values of the parameters are of concern.
2. Place the addresses of the parameters in the parameter list. We can use
address-length registers or retrieve the data by using the indexed indirect
modes. This method is sometimes referred to as call-by-name, since we are
concerned with the locations of the parameters as well as their values.
11-14 6809 Assembly Language Programming
REFERENCES
1. C. W. Gear. Computer Organization and Programming, 3rd ed., McGraw-Hill, New
York, 1980, Chapter 4.
2. S. Mazor and C. Pitchford. "Develop Cooperative Microprocessor Subroutines,"
Electronic Design, June 7, 1978, pp. 116-118. Examples are for the 8080
microprocessor.
12
Input/Output
There are two problems in the design of input/output routines one is how to :
interface peripherals to the computer and transfer data, status, and control signals;
the other is how to address I/O devices so that the CPU can select a particular one for
a data transfer. Clearly, the first problem is both more complex and more interesting.
We will therefore discuss the interfacing of peripherals here and leave addressing to a
more hardware-oriented book.
Most I/O devices do not have such convenient features. They may operate at
speeds muchslower than the processor; for example, a teletypewriter can transfer only
10 characters per second, while a slow processor can transfer 10,000 characters per sec-
12-2 6809 Assembly Language Programming
ond. The range of speeds is also very wide — sensors may provide one reading per
minute, while video displays or floppy disks may transfer 250,000 bits per second.
Furthermore, I/O devices may require continuous signals (motors or thermometers),
currents rather than voltages (teletypewriters), or voltages at far different levels than
the signals used by the processor (gas-discharge displays). I/O devices may also require
special formats, protocols, or control signals. Their word lengths may be much shorter
or much longer than the word length of the computer. These variations make the
design of I/O routines difficult and mean that each peripheral presents its own
special interfacing problem.
1. Slow devices that change state no more than once per second. Changing
their states typically requires milliseconds or longer. Such devices include
lighted displays, switches, relays, and many mechanical sensors and actua-
tors.
2. Medium-speed devices that transfer data at rates of 1 to 10,000 bits per sec-
ond. Such devices include keyboards, printers, card readers, paper tape
readers and punches, cassettes, ordinary communications lines, and many
analog data acquisition systems.
3. High-speed devices that transfer data at rates of over 10,000 bits per sec-
ond. Such devices include magnetic tapes, magnetic disks, high-speed line
printers, high-speed communications lines, and video displays.
monly used to drive several displays from the same output port. Figures 12-3 and 12-4
show the same alternatives for an input multiplexer.
Note the differences between input and output with slow devices.
1. Input data need not be latched since the input device holds the data for an
enormous length of time by computer standards. Output data must be latched
since the output device will not respond to data that is present for only a few
Input/Output 12-3
Data Outputs
Output Data
Data Bus ?
J Port ^> Inputs
Port
Selection
Strobe
Demultiplexer
=>
Data Outputs 1
Logic
Clock
Select
=>
Data Outputs 2
Data Outputs
Data Data
(7> Port Inputs
Data Outputs 1
=>
Control Select
Li> Port Inputs
Data Outputs 3
The CPU sends control information to the Control Port; that port then determines where the
Demultiplexer sends the data.
Data Inputs
Input Data c
Data Bus
C Port C Outputs
Data Inputs 1
Enable
Port n
Selection - Multiplexer
Logic Data Inputs 2
Clock
Select
Counter Data Inputs 3
Inputs
The Counter controls which input the Multiplexer routes to the Input Port.
Data Inputs
Data Data k
Input
Data Bus c Port c Outputs
Data Inputs 1
c j
Multiplexer
Data Inputs 2
< *
The control information which the CPU sends to the Control Port (with an output operation)
determines which input the Multiplexer routes to the Data Port.
CPU clock cycles. Remember that the CPU is constantly using its data bus to
perform ordinary memory transfers.
3. The major constraints on input are reaction time and responsiveness; the
major constraints on output are response time and observability.
Handshake
The standard unclocked procedure is the handshake. Here the sender indicates
the availability of data to the receiver and transfers the data; the receiver completes
the handshake by acknowledging the receipt of the data. The receiver may control the
situation by initially requesting the data or by indicating its readiness to accept data; the
sender then sends the data and completes the handshake by indicating that data is
knows that the transfer has been completed suc-
available. In either case, the sender
cessfully and the receiver knows when new data is available. The handshake procedure
can operate at any speed, since the sender and receiver (not the clock) control the
sequence of events.
Figures 12-5 and 12-6 show typical input and output operations using the
handshake method. The procedure whereby the CPU checks the readiness of the pe-
ripheral before transferring data is called "polling." Clearly, polling can occupy a large
amount of processor time if there are many I/O devices. There are several ways of pro-
viding the handshake signals. Among these are:
• Separate dedicated I/O lines. The processor may handle these as additional
I/O ports or through special lines or interrupts. The 6809 microprocessor does
not have special serial I/O lines, but the 6820 and 6821 Peripheral Interface
Adapters (or programmable parallel interface chips) do.
• Special patterns on the I/O lines. These may be single startand stop bits or
entire characters or groups of characters. The patterns must be easy to dis-
tinguish from background noise or inactive states.
Strobe
We often call a separate I/O line that indicates the availability of data or the
occurrence of a transfer a "strobe." A strobe may, for example, clock data into a latch
or fetch data from a buffer.
12-6 6809 Assembly Language Programming
Input
Acknowledge
CPU
C faction
Data Ready
k^yXf^
a. Peripheral provides data and Data Ready signal to computer I/O section.
Input
Acknowledge
Data Ready
S ^,'
11
^^"r "
->,
\-^
b. CPU reads Data Ready signal from I/O section (this may be a hardware connection, e.g., interrupt).
Input
Acknowledge
CPU &&%m wo
Section
Peripheral
Data Ready
Input
... ...,......!.. v-Tf 7
Acknowledge ;
4
.
d. CPU sends Input Acknowledge signal to I/O section which then provides Input Acknowledge
may be a hardware connection).
signal to Peripheral (this
*""^^^^~"^^^^^
Output
Ready
Ready
Output
Ready
Ready
b. CPU reads Peripheral Ready signal from I/O section (this may be a hardware connection, e.)
interrupt).
Output
Ready
Output
Ready
^. Ready
d- CPU sends Output Ready signal to Peripheral (this may be a hardware connection).
Many peripherals transfer data at regular intervals: i.e., synchronously. Here the
only problem is starting the process by lining up to the first input or marking the first
output. In some cases, the peripheral provides a clock input from which the processor
can obtain timing information. In synchronous I/O, the clock controls the speed of the
transfers, rather than the sender and receiver.
so the controller will know where to start and how much data to transfer.
Input/Output 1 2-9
TIME INTERVALS
A common problem in I/O programming is how to provide time intervals of
various lengths between operations. Such intervals are necessary to debounce
mechanical switches (i.e., to smooth their irregular transitions), to provide pulses with
specified lengths and frequencies for displays, and to time I/O operations for devices
that transfer data regularly (e.g., a teletypewriter that sends or receives one bit every 9.1
ms).
can provide time intervals of various lengths with a variety of starting and
ending conditions.
3. In software with delay routines. A delay routine has no purpose other than
to waste time; it is the computer equivalent of counting on your fingers. We
can easily specify how much time the computer is to waste, since we know the
clock speed of our particular microcomputer (this is system-dependent) and
the number of clock cycles required to execute instructions (Appendices B
and C). The problem with pure delay routines is that the processor cannot do
other tasks while it is wasting time; however, delay routines require no hard-
ware and may use processor time that would be wasted anyway.
The choiceamong these three methods depends on your application. The soft-
ware method inexpensive but may overburden the processor. The programmable
is
timers are relatively expensive but are easy to interface and may be able to handle
many complex timing tasks.
The timer in the 6846 Multifunction Support Device (ROM/IO/Timer)5 \ s availa-
ble at no extra cost if this part is being used. The part is somewhat more expensive than
simpler devices, but may be justifiable as a complete, one-chip package. 6846 devices
are used in many board-level microcomputers.
DELAY ROUTINES
A simple delay routine works as follows:
This routine does nothing except use time. The amount of time used depends on
the execution time of the various instructions. The maximum length of the delay is
12-10 6809 Assembly Language Programming
limited by the size of the register; however, the entire routine can be placed inside a
similar routine that uses another register, etc.
Be — the actual time used depends on the clock rate at which the pro-
careful
cessor running, the speed of memory accesses, and operating conditions such as
is
temperature, power supply voltage, and circuit loading which may affect the speed at
which the processor executes instructions.
The following example subroutine (starting in memory address 0030) uses the
two Accumulators to produce delays as long as 255 ms. The routine saves Accumula-
tor B and the Condition Code Register in the Hardware Stack so they are not changed.
We could use either of the general parameter passing techniques from Chapter 1 1 to
write a completely "transparent" subroutine that would not affect any registers or flags.
Of course, we would have to include the extra instructions that transfer parameters,
save and restore registers, and adjust the return address in the time budget.
Flowchart:
c Start
3
The value of MSCNT depends on the rate at which the CPU executes instruc-
tions.
Input/Output 12-11
Program a:
00C3 MSCNT EQU $C3
*
ORG $0030
0030 34 05 DELAY PSHS B,CC SAVE INCIDENTAL REGISTERS
0032 C6 C3 DLY1 LDB #MSCNT GET COUNT FOR 1 MS DELAY
0034 5A DLY DECB
0035 26 FD BNE DLY COUNT WITH B FOR 1 MS
0037 4A DECA COUNT NUMBER OF MILLISECONDS
0038 26 F8 BNE DLY1
003A 35 85 PULS PC,B,CC RESTORE INCIDENTAL REGISTERS
* AND RETURN
Time Budget:
Instruction Number of Times Executed
PSHS B.CC 1
The total time used should be (A) x 1 ms. If the memory is operating at full
speed, the instructions require the following numbers of clock cycles (according to
Appendix C).
Instruction Number of Clock Cycles
PSHS B.CC 7
LDB #MSCNT 2
DECA or DECB 2
BNE 3
PULS PCB.CC 9
Remember that PSHS and PULS require 5 clock cycles plus 1 clock cycle for each
byte pushed or pulled.
Ignoring the Jump or Branch-to-Subroutine instruction (its execution time
depends on the addressing mode used) the program takes ,
The the number of cycles required by LDB #MSCNT, DECA, and BNE DLY1; the
7 is
5 is number of cycles required by DECB and BNE DLY; the 16 is the number of
the
cycles required by PSHS B,CC and PULS PC,B,CC.
So, to make the delay 1 ms,
23 + 5 x MSCNT = N c
where N c
is the number of clock cycles per millisecond. At a 1 MHz 6809 clock rate, N c
- 1000 so
5 x MSCNT = 977
MSCNT = 1 95 (C3 6 1
) at a 6809 clock
rate of 1 MHz
Flowchart:
f Start
J
rzLr
(X) = MSCNT
(X) = (X) - 1
The value of MSCNT depends on the execution time of the instructions in the
program.
Program b:
007A MSCNT EQU $007A
*
ORG $0030
0030 34 10 DELAY PSHS X
0032 8E 007A LDX #MSCNT GET COUNT FOR 1 MS DELAY
0035 30 IF DLY LEAX -i,x COUNT X DOWN FOR 1 MS
0037 26 FC BNE DLY
0039 35 90 PULS PC,X
Time Budget:
PSHS X 1
LDX #MSCNT 1
MSCNT = 122(007A 16 )
The program can now transfer data to or from the I/O device using the instruc-
LDB DATA GET DATA
STB [A,X] SEND DATA TO LOGICAL I/O DEVICE
or
LDB [A,X] GET DATA FROM LOGICAL I/O DEVICE
STB DATA SAVE DATA IN MEMORY
12-14 6809 Assembly Language Programming
If the program uses an I/O device address repeatedly, it can load it into Index
Register X with the instruction LDX [A,X] or LEAX [A,X]. Later instructions can then
use the non-indirect indexed addressing mode with no offset.
Using this approach, a single I/O routine can transfer data to or from many
different I/O devices. The main program simply supplies the I/O routine with the index
for the device table. Compare the flexibility of this approach with the inflexibility of I/O
routines that use direct or extended addressing to transfer data to or from I/O devices
and are therefore tied to specific physical addresses.
STANDARD INTERFACES
You can use other standard interfaces besides the TTY current-loop and RS-
232 to connect peripherals to a microcomputer. Popular ones include: 7 8 '
5. Limited busses such as the Mostek/Pro-Log STD bus 13 and the Intel iSBX
These are 8-bit busses that are intended to handle small additions to
bus. 14
standard boards.
The S-100 and Multibus differ from the others listed in that they are "mother-
board" busses which connect circuit boards within a single chassis. Such a bus connects
peripheral interface control logic to the central processor and memory; a different inter-
face (either a custom job or one of the standards we have mentioned) connects the pe-
ripheral device itself to the interface card in the microcomputer chassis.
Designers often use the following LSI interface chips with the 6809
microprocessor:
1. The 6820 or 6821 Peripheral Interface Adapter. We will discuss this device
in the next chapter. It contains two 8-bit I/O ports and four serial control
lines. There are minor hardware differences between the 6820 and 6821
devices, but we will treat them as identical since they are the same from the
programmer's point of view.
2. The 6850 Asynchronous Communications Interface Adapter. This device
transforms data between the 8-bit parallel form and the serial form required in
most communications applications. We will discuss the 6850 ACIA in
Chapter 14.
similar to the 6850 ACIA but includes an on-chip baud rate generator.
4. The 6522 Versatile Interface Adapter, 15 which includes two
- 16 8-bit I/O
ports, four serial control lines, two 16-bit counter/timers, and an 8-bit shift
register.
REFERENCES
1. J.Barnes and V. Gregory. "Use Microprocessors to Enhance Performance with
Noisy Data," EDN, August 20, 1976, pp. 71-72.
2. S. V. Alekar. "M6800 Program Performs Cyclic Redundancy Checks," Electronics,
December 6, 1979, p. 167.
8. E. Teja and R. Peterson. "Selecting the Proper Bus," EDN, December 15, 1979,
pp. 231-236.
9. D. Morris. "Revised Data Interface Standards," Electronic Design, September 1,
The 6820 PIA 12 is a device which supports many modes of parallel I/O. In this
chapter we will discuss the programming of this device in some detail, and give
several examples of fundamental I/O routines. The discussion in this chapter
applies to the 6821 PIA as well; it and the 6820 appear equivalent to the programmer.
• A Data or Peripheral register that holds either input or output data. This
register is when used for output but unlatched when used for input.
latched
• A Data Direction register. The bits in this register determine whether the cor-
responding data register bits (and pins) are inputs (0) or outputs (1).
• A Control register that holds the status signals required for handshaking, and
other bits that select logic connections within the PIA.
• Two control lines that are configured by the control registers. These lines can
be used for the handshaking signals shown in Figures 12-5 and 12-6.
The meanings of the bits in the Data Direction and Control Registers are related
to the underlying hardware and are entirely arbitrary as far as the assembly language
programmer is concerned. You must either memorize them or look them up in the
appropriate tables (Tables 13-2 through 13-6).
13-2 6809 Assembly Language Programming
IRQA-
DO-
DV
D2«
Data Bus
D3« Buffers
(DBB)
DA-
D6<
D7<
jy
Bus Input
Register
(BIR)
cso *>
CS1 >•
CS2 Chip
RSO > Select
and
RSI >> R/W
Control
R/W B»>
Enable »
Reset >
Input Bus | k
Data
Direction
Interrupt CB1
Status
IRQB- Control B CB2
Address Control
Lines Register Bit Offset Address
Register Selected (Index Register or Stack Pointer) =
1 X Peripheral Register A
X Data Direction Register A
1 X X Control Register A 1
1 X 1 Peripheral Register B 2
1 X Data Direction Register B 2
1 1 X X Control Register B 3
X = Either or 1
Addresses
Each PIA occupies four memory addresses. The RS (register select) lines
choose one of the four registers, as described in Table 13-1. Since there are six
registers (two peripheral, two data direction, and two control) in each PIA, one further
bit is needed for addressing. Bit 2 of each Control Register determines whether the
other address on that side refers to the Data Direction Register (0) or to the Periph-
eral Register (1). This sharing of an external address means that
1. A program must change the bit in the Control Register in order to use the
register that is not currently being addressed.
2. The programmer must know the contents of the Control Register to deter-
mine which register is being addressed. RESET clears the Control Register
and thus addresses the Data Direction register.
Table 13-1 also shows a convenient way to address the registers in a PIA. If, as is
usually the case, the register select lines are tied to the least significant address lines
(RSO to A0 and RSI Al), the programmer can load an Index Register or Stack
to
Pointer with the address of Data (Peripheral) RegisterA and refer to the other register
by means of the constant offsets in the last column of Table 13-1.
Bit 7: status bit set by transitions on control line 1 and cleared by reading the Pe-
ripheral (Data) register
Tables 13-3 through 13-6 describe the bits in more detail. Since E is normally
tied to the 4>2 clock, you can interpret "E" pulse as "clock pulse."
7 6 5 4 3 2 1
CRA DDRA
IRQA1 IRQA2 CA2 Control CA1 Control
Access
7 6 5 4 3 2 1
CRB DDRB
IRQB1 IRQB2 CB2 Control CB1 Control
Access
Table 13-3. Control of 6820 PIA Interrupt Inputs CA1 and CB1
Notes:
1 .
t indicates positive transition (low to high)
3. The interrupt flag bit CRA- 7 is cleared by an MPU Read of the A Data Register, and CRB-7 is cleared
by an MPU Read of the B Data Register
4. If CRA-0 (CRB-0) is low when an interrupt occurs (Interrupt disabled) and is later brought high, IRQA
(IRQB) occurs after CRA-0 (CRB-0) is written to a "one."
Using the 6820 Peripheral Interface Adapter (PI A) 13-5
Table 13-4. Control of 6820 PI A Interrupt Inputs CA2 and CB2 (CRA5 (CRB5) is Low)
CRA-5 CRA-4 CRA-3 Interrupt Input Interrupt Flag MPU Interrupt Request
(CRB-5) (CRB-4) (CRB-3) CA2 (CB2) CRA-6 (CRB-6) IRQA (TRQ6)
Notes
1 . ] indicates positive transition (low to high)
3. The Interrupt flag bit CRA-6 is cleared by an MPU Read of the A Data Register and CRB-6 is cleared
CB2
CRB- CRB- CRB- Mode
5 4 3 Cleared Set
Low on the positive transition of High when the interrupt flag bit Automatic Output
the first E pulse following an CRB-7 is set by an active transi- Acknowledge
1
MPU Write "B" Data Register tion of the CB1 signal.
operation.
Low when CRB-3 goes low as a Always low as long as CRB-3 is Manual Output (Low)
result of an MPU Write in Con- low. Will go high on an MPU
1 1
trol Register "B". Write in Control Register "B"
that changes CRB-3 to "one".
Always high as long as CRB-3 is High when CRB-3 goes high as Manual Output (High)
high. Will be cleared when an a result of an MPU Write into
1 1 1 MPU Write Control Register Control Register "B".
"B" results in clearing CRB-3 to
"zero."
13-6 6809 Assembly Language Programming
CA2
CRA- CRA- CRA- Mode
6 4 3 Cleared Set
Low on negative transition of E High when the interrupt flag bit Automatic Input
after an MPU Read "A" Data CRA-7 is set by an active transi- Acknowledge
1
operation. tion of the CA1 signal.
Low on negative transition of E High on the negative edge of the Automatic Input
after an MPU Read "A" Data first"E" pulse which occurs (Read) Strobe
1 1
operation. during a deselect.
Low when CRA-3 goes low as a Always low as long as CRA-3 is Manual Output (Low)
result of an MPU Write to Con- low. Will go high on an MPU
1 1
trol Register "A". Write to Control Register "A"
that changes CRA-3 to "one".
Always high as long as CRA-3 High when CRA-3 goes high as Manual Output (High)
is high. Will be cleared on an a result of an MPU Write to
1 1 1 MPU Write to Control Register Control Register "A".
"A" that clears CRA-3 to a
"zero".
INITIALIZING A PIA
As part of the general system initialization, the program must determine how
each PIA will operate. Remember that a PIA contains a large number of logic connec-
tions, much as the processor itself does. The data stored in the control and data direction
registers activates certain connections within the PIA, much as the data loaded into the
CPU activates certain connections. The differences are that
instruction register of the
the PIA contains fewer connections than the CPU and the program rarely, if ever,
far
changes the active connections in a PIA.
The steps in determining how the PIA will operate are:
1. Address the Data Direction Registers by clearing bit 2 of each Control
Register. This allows the program to determine which I/O pins will be inputs
and which outputs. Since RESET clears the entire control register, this step is
unnecessary in the overall system startup routine.
2. Determine which I/O pins will be inputs and which outputs by loading the
appropriate combinations of 0's (for inputs) and l's (for outputs) into the
Data Direction Registers.
3. Determine how the status and control lines will operate by loading the
appropriate values into positions 0, 1,3,4, and 5 of the Control Registers.
bit
The second version is more general, since it does not change any of the other bits in the
Control Register.
After the program has addressed the Data Direction Register, it can select the
appropriate combination of inputs and outputs by storing the corresponding pattern of
0's and 1 's in that register. Some simple examples are:
The third step is clearly the most difficult, since it involves selecting the active logic con-
nections in thePIA and thus determining how the device will operate.
5. Bit 5 determines whether control line 2 is an output (1) or an input (0). Bits
3 and 4 determine how control line 2 will operate. In the pulse or automatic
strobe mode, ports A and B differ; port A produces a pulse on CA2 only after
the processor reads Data Register A, while port B produces a pulse on CB2
only after the processor writes into Data Register B.
6. You must determine the operating mode of each port of each PIA in your
system. Each port has a separate Control Register, Data Direction Register,
and Data Register.
input operation or on CB2 after an output operation are called automatic modes, since
the PI A produces the entire pulse without any explicit CPU intervention. The pro-
grammer has no control over the length or polarity of the pulse.
The mode in which PIA
Control Register determines the level of
bit 3 of the
control line 2 is called a CPU must produce changes by
manual mode, since the
explicitly setting or clearing control register bit 3. The PIA does nothing automatically.
This mode requires extra instructions, but gives the programmer complete control over
the length and polarity of pulses.
Control line 2 has the following functions in the two automatic modes:
In the mode in which the automatic pulse lasts until the next active transition on
control line 1 control line 2 is an acknowledgment. The active part of the pulse (the low
,
period) signifies that the CPU has completed its part of the most recent I/O operation;
the I/O device may start the next operation by sending data (input) or indicating its
readiness (output).
In the mode in which the automatic pulse lasts one clock cycle, control line 2 is
a strobe. The pulse indicates that the CPU has performed an I/O operation.
The program first clears bit 2 of the Control Register to gain access to the
Data Direction Register. It then makes all the data lines inputs by storing 0's
in all the bits of the Data Direction Register and sets bit 2 of the Control
Register to gain access to the Data Register (and the input port itself). The
same sequence of instructions will handle the case in which a high-to-low
transition ( falling edge) on control line 1 indicates DATA READY or PE-
RIPHERAL READY.
2. A simple output port with no control lines (for example, as needed for a set
of single LED displays)
The only difference from the previous example is that the program makes all
the data lines outputs by storing l's in all the bits of the Data Direction
Register.
3. An input port with a status input that indicates DATA READY with a low-
to-high transition (positive transition on control line 1).
CLR PIACR ADDRESS DATA DIRECTION REGISTER
CLR PIADDR MAKE ALL DATA LINES INPUTS
LDA #%00000110 MAKE DATA READY ACTIVE LOW-TO-HIGH
STA PIACR
The only difference from Example 1 is that the program sets bit 1 of the Con-
trol Register. The result is that low-to-high transitions on control line 1 will
Using the 6820 Peripheral Interface Adapter (PI A) 13-9
set bit 7 of the Control Register. This operating mode is suitable for most
encoded keyboards.
An output port that produces a brief strobe to indicate DATA READY or
OUTPUT READY. This strobe could be used to multiplex displays or to pro-
vide a DATA AVAILABLE signal to a printer.
After each instruction that writes data into PIA Data Register B, control line 2
will go low for one clock cycle. For example, the instruction
STA PIADB
willboth send data to the Data Register (and hence to the output port) and
cause a strobe on control line 2. However, the A port of a PIA will produce a
strobe only after a read operation. The sequence
willboth send the data to the output port and cause a strobe. The LDA
instructionis a "dummy read;" it has no effect except causing the strobe (and
wasting a few clock cycles). Other instructions besides LDA could serve the
same purpose; you should try to name some of them.
5. An input port with a handshake INPUT ACKNOWLEDGE strobe. The
strobe goes low when the CPU has read the data in the port and can accept
more.
CLR PIACR ADDRESS DATA DIRECTION REGISTER
CLR PIADDR MAKE ALL DATA LINES INPUTS
LDA #%00100100 CONTROL LINE 2 - HANDSHAKE ACKNOWLEDGE
STA PIACR
Control register bit 5 = 1 tomake control line 2 an output, bit 4 = to make
it a pulse, and bit 3 = make it an active-low acknowledgment that
to
remains low until the next active transition on control line 1. The port oper-
ates as follows:
LDA PIADA
willboth read the data and cause the acknowledgment. However, the B port
produce an acknowledgment only after an instruction that writes into the
will
Load Accumulator transfers 8 bits of data from the specified input pins to an
Accumulator.
Store Accumulator transfers 8 bits of data from an Accumulator to the specified
output pins.
1
You must be cautious in situations in which input and output ports do not
behave like memory locations. For example, it often makes no sense to write
data into input ports or read data from output ports. Be particularly careful if the
input port is not latched or if the output port is not buffered.
Other instructions that transfer data to or from memory can also serve as I/O
instructions. Typical examples are:
Clear places zeros on a set of output pins.
Test sets the flags according to the values of a set of input pins.
Compare sets the flags as if the values of a set of input pins had been subtracted
from the contents of an Accumulator.
Here also you must be aware of the physical limitations of the I/O ports. Be particu-
larly careful of instructions like Test, Shift, Complement, Increment, and Decrement,
which involve both read and write cycles.
We cannot overemphasize the importance of careful documentation. Often, com-
plex I/O transfers can be concealed in instructions with no obvious functions. You
must describe the purposes of such instructions carefully. For example, one could
easily be tempted to remove the dummy read and write operations mentioned earlier
since they do not appear to accomplish anything.
Note that you should not use the shift instructions, since they will change the contents
of the Control Register (why?). The following program will wait for the Ready flag to go
high:
WAITR LDA PIACR IS READY FLAG 1?
BPL WAITR NO, WAIT
How would you change these programs to examine bit 6 instead of bit 7?
The only way to clear bit 7 (or bit 6) is to read the Data Register. A dummy read
will be necessary a read operation is not normally part of the response to the
if bit being
set. If the port is used for output, the sequence
STA PIADR SEND DATA
LDA PIADR CLEAR READY FLAG
+5 v
O
6820
To CPU
PIA c>
Pushbutton
H
EXAMPLES
13-1. A PUSHBUTTON
We pushbutton to a 6809 microprocessor by means of a 6820 Pe-
will interface a
ripheral Interface Adapter. The pushbutton is a mechanical switch; pressing the button
closes the switch and connects the input bit to ground (see Fig. 13-2).
The 6820 PIA acts as a buffer; no latch is needed since the pushbutton remains
closed for many CPU clock cycles. Pressing the button grounds one bit of the PIA. The
pullup resistor ensures that the input bit is one if the button is not being pressed.
We will perform two tasks with this circuit. They are:
a. Set a memory location based on the state of the button.
Sample Cases:
Flowchart:
C Start
J
(0040) =
(0040) = 1
C End
J
Program 13- 1a:
The addresses PIACA (Control Register A), PIADDA (Data Direction Register
A), and PIADA (Data Register A) depend on how the PIA is connected in your
microcomputer. This example does not use the PIA control lines.
MASK depends on the bit to which the pushbutton is connected. It has a one in
the button position and zeros elsewhere.
13-14 6809 Assembly Language Programming
00000001 01
1 00000010 02
2 00000100 04
3 00001000 08
4 00010000 10
5 00100000 20
6 01000000 40
7 1 0000000 80
If the button is attached to bit 7 of the PI A input port, the program can use a LDA
or TST instruction to set the Sign (Negative) flag and thereby determine the button's
state. For example,
LDA PIADA IS BUTTON CLOSED (LOGIC ZERO)?
BPL DONE YES, DONE
We could also use shift instructions if the button is attached to bit 0, 6, or 7. The
sequence for bit is:
The instructions ASL or ROL can be used with bit 6 or 7. Do the contents of the PIA
data register actually change? Explain your answer.
Sample Case:
Pressing the button ten times after the start of the program should result in
(0040) = OA
In order to count the number of times the button has been pressed, we must be
sure that each closure causes a single transition. However, a mechanical pushbutton
does not produce a single transition for each closure, because the mechanical contacts
bounce back and forth before settling into their final positions. We can use a one-shot
to eliminate the bounce or we can handle it in software.
The program can debounce the pushbutton by waiting after it finds a closure.
The required delay is called the debouncing time and is part of the specifications of the
pushbutton. It is typically a few milliseconds long. The program should not examine the
pushbutton during this period because it might mistake the bounces for new closures.
The program may either enter a delay routine like the one described previously or may
simply perform other tasks for the specified amount of time.
Using the 6820 Peripheral Interface Adapter (PIA) 13-15
Even after debouncing, the program must still wait for the present closure to
end before looking for a new closure. This procedure avoids double counting. The
following program uses a software delay of 10 ms to debounce the pushbutton. You may
want to try varying the delay or eliminating it entirely to see what happens. To run this
program, you must also enter the delay subroutine into memory starting at location
0030.
Flowchart:
c Start
J
COUNT «
COUNT =
COUNT + 1
Debounce button
with 1 ms wait
Program 13-1b:
0030 DELAY EQU $0030
8001 PI ACA EQU $8001
8000 PI ADDA EQU $8000
8000 PI ADA EQU $8000
0001 MASK EQU %00000001
The three instructions beginning with the label CHKOPN determine when the
switch reopens (i.e., when the button is released). If the PIA is addressed as shown in
the last column of Table 13-1, we can load Index Register X with the address of Data
Register A, and we can then use indexed offsets to address the PIA as follows:
Original Replacement
(X) = PIADRA
CLR PIACRA CLR 1,X
CLR PIADDRA CLR ,X
STA PIACRA STA 1 , X
LDA PIADRA LDA ,X
Clearly we do not need a PIA for this simple interface. An addressable tristate buffer
would do the job at far lower cost.
The first condition can be handled by waiting until the input is not all ones, i.e.,
until a switch lead is grounded. We can handle the second condition by examining the
switch again after a delay (such as 1 or 2 seconds) and only accepting the input when it
Oi PA7
PA6
s oi
PA5
PA4
PA3
PA2
PA1
PAO
6820
PIA ^> To CPU
Common
Date Input
Binary Hex
11111110 FE
1 11111101 FD
2 11111011 FB
3 11110111 F7
4 11101111 EF
5 11011111 DF
6 10111111 BF
7 01111111 7F
This scheme is inefficient, since it requires eight bits to distinguish among eight different positions
remains the same. This delay will not affect the responsiveness of the system to the
we could use another switch (i.e., a Load switch) to tell the pro-
switch. Alternatively,
cessor when to read the selector switch.
We will perform two tasks involving the circuit of Figure 13-3. These are:
a. Monitor the switch until it is in a definite position, then determine the posi-
tionand store its binary value in a memory location.
b. Wait for the position of the switch to change, then store the new position in a
memory location.
If the switch is in a position, the lead from that position is grounded through the com-
mon line. Pullup resistors on the input lines avoid problems caused by noise.
logic). You may want to verify the double negative for yourself.
Suppose that a faulty switch or defective PIA results in the input always being
FF 16 How could you change the program so it would detect this situation?
.
We
have arranged the loop that identifies the switch position for somewhat
increased efficiency. The program initializes the position to — 1 and then increments the
position (with INCB) before shifting the input (with LSRA). What happens if you
initialize the switch position to zero and shift and check the input before incrementing
the position? The approach in which you start the program one step backward often
increases execution speed because it lets you handle the first iteration in the same way as
the subsequent ones.
13-18 6809 Assembly Language Programming
Flowchart:
c Start
J
DATA =
Switch position
POSITION -
M.
Shift DATA
right 1 bit
Yes
POSITION = (0040) =
POSITION + 1 POSITION
C End
J>
Program 13-2a:
8001 PIACA EQU $8001
8000 PI ADDA EQU $8000
8000 PI ADA EQU $8000
10
O M
4° 12
f3
To CPU
74LS148 02 PA2
oo ]4
|5
16
8-to-3 01
Encoder 00
PA1
PA0
6820
PIA :>
o 17
Common
Why does this approach work? Do the contents of the PIA Data Register actually
change? Could you use the CARRY flag instead of the ZERO flag? Explain your
answers.
This example assumes that the switch is debounced in hardware. How would you
change the program to debounce the switch in software?
Program 13-2b:
Flowchart:
The two programs both need one byte of temporary storage. How would you
last
rewrite each example to use the Hardware Stack for that storage? What are the advan-
tages and disadvantages of using the Stack? Note that it makes the programs reentrant
and more general, as well as easier to use since they do not incidentally change specific
memory locations.
Figure 13-5 shows the circuitry required to interface an LED. The LED lights
when its anode is positive with respect to its cathode (Figure 13-5a). Therefore, you
Using the 6820 Peripheral Interface Adapter (PIA) 13-21
R Anode ^h
^m*.
i
Cathode
^^ warn
+5 VO
a. Basic LED circuitry. The resistor R should limit the maximum current to 50 mA and
the average current to 1 mA
b. Interfacing an LED with positive logic. A logic 1 from the CPU lights the LED.
+5 V
O
can light the LED either by grounding the cathode and having the computer supply a
one to the anode (Figure 13-5b) or by connecting the anode to +5 volts and having the
computer supply a zero to the cathode (Figure 13-5c). Controlling the cathode is the
more common approach since most MOS or TTL I/O ports perform better in this mode.
The LED is brightest when it operates from pulsed currents of about 10 or 50 mA
applied a few hundred times per second. LEDs have a very short turn-on time (in the
microsecond range) so they are well suited to multiplexing (operating several from a
single port). LED circuits usually need peripheral or transistor drivers and current-limit-
ing resistors. MOS devices normally cannot drive LEDs directly and make them bright
enough for easy viewing.
The PIA has an output latch on each port. However, the B port is normally used
13-22 6809 Assembly Language Programming
for output, sinceit has somewhat more drive capability. In particular, the B port outputs
A. Send a Logic One to the LED (light a display that operates in positive logic or turn
off a display that operates in negative logic).
Program 13-3:
We use the B side of the PI A because of the buffering. This allows the CPU to read
the data back (if necessary) without any difficulty.
(update data)
MASKP has a '1' bit in the LED position and zeros elsewhere. Logically ORing
the contents of Accumulator A with MASKP leaves the other bit positions unchanged;
those positions may control unrelated LEDs. Note that the CPU can read the PIA data
register even when some or all the pins have been assigned as outputs.
B. Send a Logic Zero to the LED (turn off a display that operates in positive logic or
light a display that operates in negative logic).
The differences are that MASKP must be replaced by its logical complement
MASKN and ORA #MASKP must be ANDA#MASKN. MASKN has a
replaced by
zero bit in the LED position and ones elsewhere. Logically ANDing with MASKN does
not affect the other bit positions.
PB6 g
PB5
^ f
PB4 e
., , _N
From CPU
^
J Drivers d Display
J>
PB2 c
PB1 b
PBO a
Common
^zr 0+5 v
(Common- (Common-
Cathode) Anode)
PB7 may be used 1 or a decimal point LED.
+5 V
&
^
^
^
-W\i-
-WAr- ^H
^
^
^
a. Common-cathode b. Common-anode
Hexadecimal Representation
Number
Common-cathode Common-anode
3F 40
1 06 79
2 5B 24
3 4F 30
4 66 19
5 6D 12
6 7D 02
7 07 78
8 7F 00
9 67 18
Bit 7 is always zero and the others are g, f, e, d. c, b, and a in decreasing order of significance
all the segments on) and blanking inputs and outputs (for blanking leading or trailing
zeros).
Sample Problems:
(0040) = 05
Result is 5 on display
(0040) = 66
Result is a blank display
Using the 6820 Peripheral Interface Adapter (PI A) 13-25
0. Segments f, e, d, c, b, a on 5. Segments g, f. d, c, a on
a a
f b f
e c c
d d
1. Segment s c, b on 6.* Segment s g. f, e, d. c. a on
a
b f
c e c
d
Note that t he alternate representation with a off
may be res erved for the lower case letter 'b'
2. Segment s g, e. d, b. a on 7. Segment s c, b, a on
a
a
b
b
g
c
e
d
8. Segments g, f. e, d. c, b, a on
3. Segmen s g, d. c. b. a on
a
a
f b
b
e c
c
d
This is the same as LAMP TEST.
4. Segments g, f, c, b on 9. Segments g, f, c, b. a on
Lower-case Letters
Upper-case Letters
and Special Characters
Hexadecimal Hexadecimal
Representation Representation
Letter Character
Common- Common- Common- Common-
cathode anode cathode anode
A 77 08 b 7C 03
C 39 46 c 58 27
E 79 06 d 5E 21
F 71 0E h 74 OB
H 76 09 n 54 2B
I 06 79 5C 23
J IE 61 r 50 2F
L 38 47 u 1C 63
3F 40 40 3F
P 73 OC ? 53 2C
U 3E 41
Y 66 19
Source Program:
Flowchart:
c Start
CODE - Blank
DATA (0040)
Send CODE
to display
End ")
c
after each output operation, thus directing the data to the next display. RESET initial-
izes the decade counter to 9 so that the first output operation clears the counter and
directs data to the first (actually, the zeroth) display.
The next program uses a transparent 1 ms delay routine (described earlier in this
chapter) to pulse each often common-cathode displays for 1 ms. An observer will see a
continuous ten-digit display much like the ones typical of electronic calculators,
watches, and point-of-sale terminals.
Purpose: Continuously display the contents of memory locations 0040 through 0049 on
ten 7-segment displays that are multiplexed with a counter and a decoder. The
most significant (leftmost) digit is in memory location 0040.
Sample Problem:
(0040) * 66
(0041) = 3F
(0042) = 7F
(0043) = 7F
(0044) m 06
(0045) = 5B
(0046) = 07
(0047) m 4F
(0048) = 6D
(0049) OS 7D
The number on the displays is 4088127356
13-28 6809 Assembly Language Programming
From CPU
Reset
Program 13-4b:
0030 DELAY EQU $0030
8003 PIACB EQU $8003
8002 PIADDB EQU $8002
8002 PIADB EQU $8002
*
0000 ORG $0000
0000 7F 8003 CLR PIACB ADDRESS DATA DIRECTION REGISTER
0003 86 FF LDA #$FF MAKE ALL DATA LINES OUTPUTS
0005 B7 8002 STA PIADDB
0008 86 2C LDA #%00101 100 MAKE CB2 A BRIEF PULSE,
* ADDRESS I/O
000A B7 8003 STA PIACB
OOOD 8E 0040 SCAN LDX #$40 POINT TO START OF DATA
0010 C6 OA LDB #10 NUMBER OF DISPLAYS = 10
0012 A6 80 DSPLY LDA ,X+ GET DATA FOR A DISPLAY
0014 B7 8002 STA PIADB SEND DATA TO DISPLAY
0017 9D 30 JSR DELAY WAIT 1 MS
0019 5A DECB COUNT DISPLAYS
001A 26 F6 BNE DSPLY
001C 20 EF BRA SCAN START ANOTHER SCAN
Control register bit 5 = 1 to make CB2 an output, bit 4 = to make a pulse, and
it
bit 3 = 1 to make it a brief pulse lasting one clock cycle. We have assumed here that
subroutine DELAY (starting at address 0030) provides a transparent 1 ms wait (i.e., it
Because of their high data rates, you cannot handle these I/O devices casually. If
the processor does not provide the appropriate service, the system may miss input data
or produce erroneous output data. You are therefore working under much more exact-
ing constraints than in dealing with simpler devices. Interrupts are a convenient method
for handling complex I/O devices, as we shall see in Chapter 15.
SYNCHRONIZATION
Peripherals such as keyboards, teletypewriters, cassettes, and floppy disks pro-
duce their own internal timing. These devices provide streams of data separated by
specific timing intervals. The computer must synchronize the initial input or output
operation with the peripheral clock and then provide the proper interval between sub-
sequent operations. A simple delay loop like the one shown previously can produce
the time interval. The synchronization may require one or more of the following pro-
cedures:
line and wait until the appropriate bit of the PIA control register is set.
2. Finding the center of the time interval during which the data is stable. We
would prefer to determine the value of the data at the center of the pulse
rather than at the edges, where the data may be changing. Finding the center
requires a delay of one-half of a transmission interval (bit time) after the
edge. Sampling the data at the center also means that small timing errors have
little effect on the accuracy of the reception.
3. Recognizing a special starting code. This is easy if the code is a single bit or if
we have some timing information. The procedure is more complex if the code
is long and could start at any time. Shifting will be necessary to determine
where the transmitter is starting its bits, characters, or messages (this is often
called a search for the correct "framing").
4. Sampling the data several times. This reduces the probability of receiving
data incorrectly from noisy lines. Majority logic (such as best 3 out of 5 or 5
out of 8) can be used to decide on the actual data value.
Reception is, of course, much more difficult than transmission, since the periph-
eral controls the receptionand the computer must interpret timing information gener-
ated by the peripheral. In transmission, the computer provides the proper timing and
formatting for a specific peripheral.
Step 3 is unnecessary if the field is a single bit, since the Zero flag will contain the
Using the 6820 Peripheral Interface Adapter (PI A) 13-31
complement of that bit after Step 2 (try it!). A Shift or Load instruction can replace Step
2 if the field is a single bit and occupies the most significant, or next to
least significant,
most significant bit position (positions 0, 7, or 6). These positions are often reserved for
the most frequently used status information. You should try to write the required
instruction sequences for the 6809 processor. Note, in particular, the use of the Bit Test
instruction. This instruction performs a logical AND between the contents of the
Accumulator and the contents of a memory location but does not save the result; the
flags are set as follows:
Zero flag = 1 if the logical AND produces a zero result, if it does not.
Sign flag = bit 7 of the result of the logical AND.
Here again the procedure is simpler if the field is a single bit and occupies a posi-
tion at either end of a data byte.
Some examples of separating and combining status bits are:
1. A 3-bit field in bit positions 2 through 4 of a PI A Data Register is a scaling fac-
tor. Place that factor in Accumulator A.
2. Accumulator A contains a 2-bit field that must be placed in bit positions 3 and
4 of a PI A Data Register.
*
*MOVE DATA TO FIELD POSITIONS
*
ASLA SHIFT DATA TO BIT POSITIONS 3 AND 4
AS LA
ASLA
ANDA #%00011000 CLEAR OUT OTHER BITS
*
COMBINE NEW FIELD POSITIONS WITH OTHER DATA
*
PSHS A SAVE NEW FIELD VALUE AT TOP OF STACK
LDA PIADR CLEAR OLD FIELD VALUE
ANDA #%11100111
ORA ,S+ INSERT NEW FIELD VALUE AND CLEAR STACK
STA PIADR
The instruction ORA ,S+ not only logically ORs the accumulator with the data we
13-32 6809 Assembly Language Programming
0+5 V
Key 1
ii
±
O +5 V
Key 2
±
O +5 V
Key3
_L
saved at the top of the Hardware Stack, but it also increments the Hardware Stack
Pointer and thus removes the data from the Stack.
Matrix Keyboard
Keyboards with more than eight keys require more than one input port and
therefore multibyte operations. This is particularly wasteful if the keys are logically sepa-
rate, as in a calculator or terminal keyboard where the user will only strike one at a time.
The number of input lines required may be reduced by connecting the keys into a
matrix, as shown in Figure 13-11. Now each key represents a potential connection
between a row and a column. The keyboard matrix requires n + m external lines,
where n is the number of rows and m is the number of columns. This compares to n x
m external lines if each key is separate. Table 13-10 compares the number of keys
required by typical configurations.
Key 2
vA yA V4
Key Key 1
Row
Key 4 Key 5
Key 3
vA VA vA
Row 1
Row 2
Key 6,
v^^w-v/
^ <£. <£.
Pressing a key connects a row to a column. For example, pressing key 2 connects row to column 2.
3x3 9 6
4X4 16 8
4X6 24 10
5X5 25 10
6X6 36 12
6X8 48 14
8X8 64 16
13-34 6809 Assembly Language Programming
Q+5 V
r
Key 1 Key 2
vA
00 Row
VA y4 V4
02 ^ Row 2
10 II
PIA
Input
Port
\7
Data Bus (to CPU)
Keyboard Scan
A program can determine which key has been pressed by using the external
lines from the matrix. The usual procedure is a "keyboard scan." We ground Row
and examine the column lines. If any lines are grounded, a key in that row has been
pressed, causing a row-to-column connection. We can determine which key was pressed
by determining which column line is grounded; that is, which bit of the input port is
zero. If no column line is grounded, we proceed to Row 1 and repeat the scan. Note that
we can check to see if any keys at all have been pressed by grounding all the rows at
once and examining the columns.
The keyboard scan requires that the row lines be tied to an output port and the
column lines to an input port. Figure 13-12 shows the arrangement. The CPU can
Using the 6820 Peripheral Interface Adapter (PIA) 13-35
ground a particular row by placing a zero in the appropriate bit of the output port and
ones in the other bits.
The CPU can determine the state of a particular column by examining the
appropriate bit of the input port.
Flowchart:
C Start
J
Ground all
keyboard rows
Masking off the column bits eliminates any problems that could be caused by the
unused input lines.
states of the
.
We could generalize the routine by naming the output and masking patterns:
We could then use these names in the program; changing to a different keyboard
would require only a change in the definitions and a re-assembly.
Of course, a 3 x 3 or 4 x 4 keyboard only needs one port of a PI A. Rewrite the
program to use only port A.
1 Set key number to 1 , keyboard output port to all ones except for a zero in bit
0, and row counter to number of rows.
2. Fetch the column inputs by reading the input port.
3. If any column inputs are zero, proceed to Step 7.
4. Add the number of columns to the key number to reach next row.
5. Update the contents of the output port by shifting the zero bit left one posi-
tion.
6. Decrement row counter. Go to Step 2 if any rows have not been scanned;
otherwise, go to Step 9.
9. End of program.
This program does not wait for the operator to press a key, so the key must be
pressed before the program is executed. How would you modify the program to wait for
at least one key to be pressed?
Program 13-5b:
8001 PI ADA EQU $8001
8000 PI ADDA EQU $8000
8000 PI ADA EQU $8000
8003 PIACB EQU $8003
8002 PIADDB EQU $8002
8002 PIADB EQU $8002
*
0000 ORG $0000
0000 7F 8001 CLR PIACA ADDRESS DATA DIRECTION REGISTERS
0003 7F 8003 CLR PIACB
0006 7F 8000 CLR PI ADDA MAKE A SIDE DATA LINES INPUTS
0009 86 FF LDA #$FF MAKE B SIDE DATA LINES OUTPUTS
000B B7 8002 STA PIADDB
000E 86 04 LDA #%0000 0100 ADDRESS DATA REGISTERS
0010 B7 8001 STA PIACA
0013 B7 8003 STA PIACB
0016 86 FE LDA #%1111 1110 START BY GROUNDING ROW ZERO
0018 B7 8002 STA PIADB
001B 86 03 LDA #3 COUNTER = NUMBER OF ROWS
001D 97 40 STA $40
001F C6 FF LDB #$FF KEY NUMBER = -1
0021 B6 8000 FROW LDA PI ADA GET COLUMN INPUTS
0024 84 07 ANDA #%0000 0111 MASK OFF COLUMN BITS
0026 81 07 CMPA *%0000 0111 ARE ANY KEYS CLOSED IN THIS
ROW?
Using the 6820 Peripheral Interface Adapter (PI A) 13-37
Flowchart:
c Start
:>
KEY NUMBER = -
COUNTER = Number
of rows
Keyboard output
port = 1 111111Q 2
KEY NUMBER =
KEY NUMBER +
number of columns
COUNTER =
COUNTER - 1
Yes
Each time a row scan fails, we must add the number of columns (3 in the exam-
ple) to the key number to move to the next row (try the procedure on the keyboard in
Figure 13-12).
We could generalize the program by making the number of rows, the number of
columns, and the masking patterns into named parameters with Equate (EQU) direc-
tives.
What result does the program produce in Accumulator B if no keys are being
pressed? Change the program so that it starts the scan over again in that case.
An alternative approach is to use the bidirectional capability of the PIA. 7 The pro-
cedure would be:
Keyboard
PAO-PA7
c data inputs
Keyboard
CA1
strobe
the PIA control register (a simple software change) rather than by rewiring a bread-
board. For example, changing the active edge on the strobe line requires the changing of
one bit in a program, wherease it might require additional parts and rewiring on a bread-
board.
Be careful, however, of the fact that the PIA does not contain an input latch. An
actual interface may require a latch if the keyboard is not guaranteed to hold its data.
The latch can also be controlled by the strobe signal.
Task: Wait for an active-low strobe on control line CA1 and then load the keyboard
data into Accumulator A.
Note that reading the data from the Data Register clears the status bit (this circui-
try is part of the 6820 PIA).
Flowchart:
c Start
J
Read Data
register
c End
D
The hardware must hold the control lines in a logic one state while RESET is
active to prevent the accidental setting of status flags. An initial read of the Data
Registers in the startup routine may be used to clear the PIA status bits. 9
Program 13-6:
8001 PIACA EQU $8001
8Q00 PIADDA EQU $8000
8000 PIADA EQU $8000
To set control register bit 7 on low-to-high transitions on the keyboard strobe line,
simply replace LDA#%00000100 with LDA#%00000110.
13-40 6809 Assembly Language Programming
If we tied the keyboard strobe line to CA2, control register bit 6 would then serve
as the status latch.
Show that reading the Data Register clears the status bit, indicating that the CPU
has read the most recent data and allowing the next input operation to occur. Hint: Save
the contents of the PI A control register in memory before and after the instruction LDA
PI AD A is executed. What happens if you replace LDA with ST A? How about TST,
CLR, COM, ADD? Remember that writing data into the Data Register does not clear
the status nor does writing data into or reading data from the control register. What
bit,
happens you replace LDA PIADA with LDA PIACA or STA PIACA?
if
One reason why we are concerned with the effects of instructions on PIA
registers is that we may want to use the control lines for purposes that have nothing
to do with the data ports. For example, we may be using a PIA to interface a simple pe-
ripheral (e.g., a set of switches or single LEDs) that does not require any status or con-
trol lines. The control lines are then available as serial I/O lines at no additional hard-
ware cost. The only problem is that we must manipulate these lines using facilities that
are provided on the assumption of a direct connection between the serial lines and the
parallel data port.
Figure 13-15 illustrates the interfacing of the NE5018 to a 6809 system. Note
that port B of the PIA automatically produces the active-low pulse required to latch the
data into the D/A converter; CB2 acts as an OUTPUT READY signal, indicating that
the CPU has sent data to the output port. Remember that in the brief pulse mode, CB2
goes low automatically on the clock pulse following a write operation on Data Register
B, and remains low until the next clock pulse (see Table 13-5). The control register bits
that cause the PIA to operate this way are:
Note that the PIA contains an output latch. The data therefore remains stable dur-
ing and after conversion, even though the processor only leaves it on the data bus for
one clock cycle. Output latches are essential in microcomputer systems, since the pro-
Using the 6820 Peripheral Interface Adapter (PI A) 13-41
Ew
g E 5
3 O
CO z <o <o
O
IH^AAHl
& -VW-*
QO
CD .2
S Q
S
3 5
^*-o
\i^T'
sio>
-V hVVVh >-*+At-\
<
*
l -w\»-
ceO oc<
> >
13-42 6809 Assembly Language Programming
6820 NE6018
PIA D/A
Converter
i/
^ Analoa
Output
CB2 LE
cessor uses its data bus constantly to transfer data and instructions to and from memory.
The converter typically requires only a few microseconds to produce analog outputs, but
other peripheralsmay need the data for much longer periods.
In applications where eight bits of resolution are not enough, you can use the
widely available 10 to 16-bit converters. Ones that are advertised as "microprocessor-
compatible" usually have separate data ports for the most and least significant bytes.
Such devices are much easier to interface than devices that only accept all the data at one
time through a single port.
The PIA serves as both a parallel data port and a serial control port. CB2 pro-
vides a pulse that lasts one clock cycle after the CPU latches output data into the PIA.
This pulse is long enough to meet the requirements (typically 400 ns) of the NE5018
converter.
Flowchart:
c Start
3
Data = (0040)
Send data to
converter and
latch it
c End
}
Using the 6820 Peripheral Interface Adapter (PI A) 13-43
Program 13- 7:
8003 PIACB EQU $8003
8002 PIADDB EQU $8002
8002 PIADB EQU $8002
*
0000 ORG $0000
0000 7F 8003 CLR PIACB ADDRESS DATA DIRECTION REG
0003 86 FF LDA #$FF MAKE ALL DATA LINES OUTPUT
0005 B7 8002 STA PIADDB
0008 86 2C LDA #%00101100 ADDRESS DATA REGISTER,
000A B7 8003 STA PIACB PROVIDE BRIEF STROBE
OOOD D6 40 LDB $40 GET DATA
OOOF F7 8002 STB PIADB SEND DATA TO D/A CONVERTER
* AND LATCH
0012 3F SWI
The PIA produces the Load pulse automatically after the CPU stores the data in
the Data Register. No Although automatic opera-
explicit instructions are necessary.
tions like this save time and memory, they also result in documentation problems since
there is no record in the program of when they occur. To understand the operation of
this interface, you would need a detailed understanding of the 6820 device as well as a
hardware schematic and a program listing. Such requirements make maintenance and
updating difficult.
The automatic pulse lasts only one clock cycle. If this is not long enough (or if an
active-high pulse is necessary), we could use the level output from CB2. This operating
mode is often called a manual mode, since the PIA does not produce any pulses auto-
matically. The program to use the mode would be:
This approach requires more instructions, but it produces a longer pulse and is
easier to understand. Here bit 4 of the PIA control register is set to make CB2 a level
with the value of bit 3. We can then set and clear bit 3 using the logical instructions (OR
with T to set, AND with '0' to clear).
The only precaution one must take in using it is to avoid changing any of the other
bits in the PIA control register, since they have unrelated functions. Using the logical
OR and AND
instructions makes the procedure independent of the contents of the PIA
control register, since only bit 3 is changed.
NATIONAL
MM63B7 8-bit A/D converter
General Description
The MM5357 is an 8-bit monolithic A/D converter using P-channel ion-implemented MOS technology. It
contains a high input impedance comparator, 256 series resistors and analog switches, control logic and
output latches. Conversion is performed using a successive approximation technique where the unknown
analog voltage is compared to the resistor tie points using analog switches. When the appropriate tie
point voltage matches the unknown voltage, conversion is complete and the digital outputs contain an 8-
bit complementary binary word corresponding to the unknown. The binary output is tri-state to permit
bussing on common data lines.
Timing Diagram
Clock Input
Start
+5 V
OV
+5 V
nnnAAAAAAn/u
—
Conversion
v JTV.
— * *- 4h
EOC +5 V
40 x
V —» (1/f).
Output Enable +5 V
V »
+5 V
Data
V
— (TrUsta tej _ _ — j>
cz^c h
Enable Delay Disable Delay
Connection Diagram
2-4. 18
2-3. 17 ,
2 -5
2-2. 16 .2-6
(MSB) 2" 1 •
MM5357 15 +Vref
R Network AD 14 2-7
STRT CONV • Converter 1 • 2-8 (LSB)
Output Enable • 12
v GG - 11 Clock
EOC 10 •v ss
Typical Application
+5V
+5V
GND
-5V RNET Digital Output
-12V
Analog Input
Clock
'N
MM5357 7
A/D
Start Conversation SC Converter z2-8
au LSB
Output Enable EOC End of Conversion
Figure 13-16 contains a general description and a timing diagram for the
National MM5357 8-bit A/D converter. The device contains output latches and tristate
data outputs. A pulse on the Start Conversion (STRT CONV) line starts conversion of
the analog input; after about 40 clock cycles (the converter requires a TTL level clock
with a minimum pulse width of 400 ns), the result will go to the output latches and the
End of Conversion (EOC) output will indicate this by going high. Data is read from the
latches by applying a T to the OUTPUT ENABLE input. Figure 13-17 shows the con-
nections for the device and some typical applications circuits.
Figure 13-18 shows the interface between the 6809 microprocessor and the 5357
A/D converter. Control line CA2 is used in the level (manual) output mode to provide
an active-high Start Conversion pulse of sufficient length. The End of Conversion signal
is tied to control line CA1 so bit 7 of PI A Control Register A is set when EOC goes high.
The important transition on the End of Conversion line is the leading edge (low-to-high
transition), which indicates the completion of the conversion. Here we are using the
6820 PIA to handle parallel input, serial input, and serial output, since the A/D con-
verter requires a complete handshake. The OUTPUT ENABLE pin on the converter is
tied high, since we are not placing the data directly on the microprocessor's tristate data
bus. Note (see Fig. 13-16) that the converter's data outputs are complementary binary
(an all zeros output is full scale).
13-46 6809 Assembly Language Programming
6820 National
PIA 5357
A/O
Data Bus Analog
to CPU C PA0-PA7
c Converter
Input
STRT
CA1 CA2 EOC CONV
Program 13-8:
8001 PIACA EQU $8001
8000 PI ADDA EQU $8000
8000 PI ADA EQU $8000
0000 ORG $0000
0000 7F 8001 CLR PIACA ADDRESS DATA DIRECTION REGISTER
0003 7F 8000 CLR PIADDA MAKE ALL DATA LINES INPUTS
0006 86 36 LDA #%00110 110 BRING START LOW, TRIGGER ON
0008 B7 8001 STA PIACA EOC GOING HIGH
000B 8A 08 ORA #%00001 000 BRING START CONVERSION HIGH
000D B7 8001 STA PIACA
0010 84 F7 ANDA #%11110 111 BRING START CONVERSION LOW
0012 B7 8001 STA PIACA
0015 B6 8001 WTEOC LDA PIACA HAS CONVERSION BEEN COMPLETED?
0018 2A FB BPL WTEOC NO, WAIT
001A B6 8000 LDA PIADA YES, FETCH DATA FROM CONVERTER
001D 43 COMA COMPLEMENT DATA TO PRODUCE TRUE
VALUE
001E 97 40 STA $40 SAVE DATA IN MEMORY
0020 3F SWI
This program would use less time and memory if we used Index Register X to
address the PIA. Rewrite the program to do this. We have used explicit addresses in the
interest of clarity.
The PIA control register bits are determined as follows:
Flowchart:
Is
conversion
complete
? ^S' (Has EOC gone high?)
I ")
C End
Here the PIA serves as a parallel data port, a serial status port, and a serial control
port. An read of the Data Register in the startup routine would clear the status
initial
flags originally and eliminate problems that might be caused by stray pulses on the con-
trol lines.
teletypewriter.
3. The character is usually 7-bit ASCII with the least significant bit transmitted
first.
4. The most significant bit is a Parity bit, which may be even, odd, or fixed at
zero or one.
5. Two stop bits (logic Ts) follow each character to provide a minimum separa-
tion between characters.
Figure 13-19 shows the format. Note that each character requires the transmission
of eleven bits, of which only seven contain information. Since the data rate is ten charac-
ters per second, the bit rate is 10 x 11, or 110 Baud. Each bit therefore has a width of
1/110 of a second, or 9.1 milliseconds. This width is an average; the teletypewriter does
not maintain it to any high level of accuracy.
13-48 6809 Assembly Language Programming
Character
Spare
is
CO')
ASCII 'E'
\
^
•V
'0'
7 Data Bits
'0'
T
\
'0'
Parity
Bit
1
Stop
Bit
Stop
Bit
Step 1. Look for a Start bit (a logic zero) on the data line.
Step 2. Center the reception by waiting one-half bit time, or 4.55 milliseconds.
Step 3. Fetch the data bits, waiting one bit time before each one. Assemble the
data bits into a word by first shifting the bit to the Carry and then cir-
cularly shifting the data with the Carry. Remember that the least signifi-
cant bit is received first.
Step 4. Generate the received Parity and check it against the transmitted Parity.
Step 5. Fetch the Stop bits (waiting one bit time between inputs). If they are not
correct (if both Stop bits are not one), indicate a "framing error."
Step 2. Transmit the seven data bits, starting with the least significant bit.
The transmission routine must wait one bit time between output operations.
start
C )
Wait one-half
bit time
COUNT = 8
Wait one bit time
DATA =
COUNT =
COUNT - 1
COUNT =
COUNT -1
Generate
received parity
End
}
Figure 13-20. Flowchart for Receive Procedure
1
C Start
J
Carry = Start bit
Get output data
Shift data left
circularly with Carry
COUNT = 1
Send data to
Output Port
I
Shift data right
circularly with Carry
Carry = 1 (Stop bit)
COUNT =
COUNT -1
Program 13-9a:
Assume that the serial port is bit 7 of the PI A and that no parity or framing check
necessary. 8001 PIACA EQU $8001
8000 PI ADDA EQU $8000
8000 PIADA EQU $8000
(Delay program)
The DELAY subroutine is the same as before. Remember that bit of the data
must be transmitted first.
In actual applications, you should place a logic T
on the teletypewriter line as part
of the startup routine, since that line should normally be in the mark (1) state.
Each character consists of 11 bits, beginning with a start bit ('0') and ending with
two stop bits Cl's). The instruction ORCC #%00000001 sets the least significant bit of
the Condition Code Register (the Carry flag), thus generating a logic T which RORA
then shifts into the most significant bit of Accumulator A.
We can generate parity by counting bits as shown in Chapter 6. The program is
13-52 6809 Assembly Language Programming
as follows:
Accumulator B contains the number of T bits in the data. The least significant bit
of Accumulator B is therefore an even Parity bit.
UART
These procedures are sufficiently common and complex to merit a special LSI
device: theUART, or Universal Asynchronous Receiver/Transmitter. 20 The UART
will perform the reception procedure and provide the data in parallel form and a Data
Ready signal. It will also accept data in parallel form, perform the transmission pro-
cedure, and provide a Peripheral Ready signal when it can handle more data. UARTs
may have many other features, including:
1. Ability to handle various bit lengths (usually 5 to 8), parity options, and num-
bers of Stop bits (usually 1, 1-1/2, and 2).
2. Indicators for framing errors, parity errors, and "overrun errors" (failure to
read a character before another one is received).
UARTs act as four parallel ports: an input data port, an output data port, an input
status port, and an output control port. The status bits include error indicators as well as
Ready flags. The control bits select various options. UARTs are inexpensive ($5 to $50,
depending on features) and easy to use.
PROBLEMS
13-1. An On-Off Pushbutton
Purpose: Each closure of the pushbutton complements (inverts) all the bits in memory
location 0040. The The program should con-
location initially contains zero.
tinuously examine the pushbutton and complement location 0040 with each
Using the 6820 Peripheral Interface Adapter (PI A) 13-53
Sample Case:
back to zero, the third back to FF l6 etc. Assume that the pushbutton is debounced in
,
Sample Problem:
Sample Problem:
Result: (0040) = 02
Purpose: A set of eight switches should have their positions reflected on eight LEDs.
That is to say, if the switch is closed (zero), the LED should be on; otherwise,
the LED should be off. Assume that the CPU output port is connected to the
cathodes of the LEDs.
Sample Problem:
How would you change the program so that a switch attached to bit 7 of Port A of
PIA#2 determines whether the displays are active (i.e., if the control switch is closed,
the displays attached to Port B reflect the switches attached to Port A; if the control
switch open, the displays are always off)? A control switch is useful when the displays
is
Sample Problem:
(0040) = 04
Entries are 7, 2, 2, 4
Result: (0041) = 07
(0042) = 02
(0043) = 02
(0044) * 04
Sample Problem:
Entries are H, E, L, L.
(0041) = 45 'E'
(0042) = 4C V
(0043) = 4C 'L*
(0044) = 4F '0'
(0045) * 2E '.'
Using the 6820 Peripheral Interface Adapter (PIA) 13-55
Purpose: The program should generate a square wave, as shown in the next figure,
using a D/A converter. Memory location 0040 contains the scaled amplitude
of the wave, memory location 0041 the length of a half cycle in milliseconds,
and memory location 0042 the number of cycles.
Assume that a digital output of 80 16 to the converter results in an analog output of
zero volts. In general, a digital output of D results in an analog output of (D-80)/80 x
-V REF volts.
Sample Problem:
(0040) = A0 16
(0041) = 04
(0042) = 03
Result:
+ V REF
I ^ ==f===±==f==^==d==*c=J-
O - V REF 4 ms
Time-
The program produces 3 pulses of amplitude V REF I A with a half cycle length of 4 ms.
Result: (0040) = 85 16
REFERENCES
1. A. Osborne et al. An Introduction to Microcomputers: Volume 2 — Some Real
Microprocessors, pp. 9-45 through 9-54.
2. J.Gilmore and R. Huntington. "Designing with the 6820 Peripheral Interface
Adapter," Electronics, December 23, 1976, pp. 85-86.
3. The TTL Data Book for Design Engineers, Texas Instruments Inc., P.O. Box 5012,
Dallas, Tex. 75222, pp. 7-151 through 7-156.
4. E. Dilatush. "Special Report: Numeric and Alphanumeric Displays," EDN, Janu-
ary 5, 1978, pp. 26-35.
5. The TTL Data Book for Design Engineers, Texas Instruments Inc., P.O. Box 5012,
Dallas, Tex. 75222, pp. 7-22 through 7-34.
21. "Interface Between Data Terminal Equipment and Data Communications Equip-
ment Employing Serial Binary Data Interchange," EIA RS-232C, Electronic
Industries Association, 2001 I Street N.W., Washington, D.C. 20006, August
1969.
J. Kane et al. An Introduction to Microcomputers: Volume 3 — Some Real Support
Devices, Osborne/McGraw-Hill, Berkeley, Calif, pp. J5-9 through J5-14.
must retain a copy in RAM. We will refer to the addresses as ACIADR (the receive
data register when reading, the transmitted data register when writing), ACIASR
(the read-only status register), and ACIACR (the write-only control register).
ACIASR and ACIACR are the same physical address.
14-2 6809 Assembly Language Programming
Clock Parity
Transmit Clock -
Generator Generator
Enable -
I Clear-to- Send
Status
Register
Interrupt Interrupt
O Logic Request
Data
Data Carrier
Bus
Detect
Buffers
Request -
On Control
Register
to-Send
Receive
Control
Parity
Check
Receive
Data
Register
Receive
Shift
Register
Clock
Receive Clock-
Generator
Sync
Receive Data
Logic
Buffer Address
7 Data Bit 7*" Data Bit 7" Receive Interrupt Interrupt Request
Enable (CR7) (IRQ)
*
Leading bit = LSB = Bit
" Data bit will t >e zero in 7-bit plus parity modes
"* Data bit is "d on't care" in 7-bit plus parity modes
SPECIAL FEATURES
Note the following special features of the 6850 ACIA:
1. Read and write cycles address physically distinct registers. Therefore, you
cannot use the ACIA registers as addresses for instructions like Increment,
Decrement, or Shift, which involve both read and write cycles.
2. The ACIA Control register cannot be read by the CPU. You will have to
save a copy of the Control register in memory if the program needs its value.
3. The ACIA has no Reset input. It can be reset only by placing ones in Control
register bits and 1. This procedure (called "Master Reset") is necessary
before the ACIA is used, in order to avoid having a random starting
character.
+1
1 -M6
1 + 64
1 1 Master Reset
The ACIA requires an external clock. Typically, 1760 Hz is supplied and the
-5-
16 mode (Control register bit 1 = 0, bit = will use
1) is used. The ACIA
the clock to center the reception and to avoid false Start bits caused by noise
on the lines.
The Data Ready (receive data register full, or RDRF) flag is bit of the
Status register. The Peripheral Ready (transmit data register empty, or
TDRE) flag is bit 1 of the Status register.
)
)
PROGRAM EXAMPLES
14-1. RECEIVE DATA FROM TTY
Purpose: Receive data from a teletypewriter using a 6850 ACIA and store the data in
memory location 0060.
Program 14-1:
8010 ACIACR EQU $8010
8010 ACIASR EQU $8010
8011 ACIADR EQU $8011
Bit 1—0, Bit 0=1 for -H6 clock (1760 Hz must be supplied)
The received data status flag is bit of the ACIA Status Register. What would
happen if we tried to replace
LDA ACIASR
LSR A
with the single instruction
LSR ACIASR
Remember that the Status and Control registers share an address but are physically dis-
tinct.
Assume that the priority of the errors is from left to right in the ACIA status
register (i.e., parity errors have over overrun errors which, in turn, have priority
priority
over framing errors if more than one error has occurred).
14-6 6809 Assembly Language Programming
Program 14-2:
8010 ACIACR EQU $8010
8010 ACIASR EQO $8010
8011 AC I ADR EQU $8011
REFERENCES
A. Osborne et al. An Introduction to Microcomputers: Volume 2 — Some Real
Microprocessors, pp. 9-55 through 9-61.
K. Fronheiser. "Device Operation and System Implementation of the
Asynchronous Communications Interface Adapter," Motorola Semiconductor
Products Inc. Application Note AN-754, Phoenix, AZ, 1975.
J. Volp. "Software Switches Baud Rate," EDN, November 5, 1979, p. 83.
15
Interrupts
Interrupts are inputs that the CPU examines as part of each instruction cycle.
These inputs allow the CPU to react to asynchronous events more efficiently than by
polling devices.The use of interrupts generally involves more hardware than does
ordinary (programmed) I/O, but interrupts provide a faster and more direct response. 1
Why use interrupts? Interrupts allow events such as alarms, power failure, the
passage of a certain amount of time, and peripherals having data or being ready to
accept data to get the immediate attention of the CPU. The program does not have to
examine (poll) every potential source, nor need the programmer worry about the
system missing events.
An interrupt system is like the bell on a telephone — it rings when a call comes in
so that you don't have to pick up the receiver occasionally to see if someone is on the
line. The CPU can go about its normal business (and get a lot more done). When some-
thing happens, the interrupt alerts the CPU and forces it to service the input before
resuming normal operations. Of course, this simple description becomes more compli-
cated (just like a telephone switchboard) when there are many interrupts of varying
importance and tasks that cannot be interrupted.
There are many different answers to these questions. The aim of all the imple-
mentations, however, is to have the CPU respond rapidly to interrupts and resume nor-
Priority
Interrupts 1 5-3
Disadvantages of Interrupts
The advantages of interrupts are obvious, but there are also disadvantages.
These include:
disa bled. T he IRQ mask bit (or I flag) is bit 4 of the Condition Code Register;
the FIRQ mask bit (or F flag) is bit 6 of the Condition Code Re gister. The E
(entire) flag (bit 7 of the Condition Code Register) distinguishes FIRQ inter-
rupts from other interrupts as we will describe later. As might be expected,
Reset sets both the I and F bits, thus starting the processor with both inter-
rupts disabled. This allows the programmer to initialize the system before
allowing interrupts.
CPU also disables the fast interrupt (FIRQ); that is, it sets bit 6 (the F flag) of
the Condition Code Register.
2. If the CPU is not executing CWAI or SYNC ( we will discuss those instruc-
tions later), it clears the E FIRQ and sets it otherwise.
flag in response to
The E flag is bit 7 Code Register.
of the Condition
3. The CPU saves ei ther t he Program Counter and the Condition Code
Register (input is FIRQ) or all the user registers (any other input or
instruction) in the Hardware Stack. Figure 15-1 shows the order in which
15-4 6809 Assembly Language Programming
Before After
ssss - 3 -Hardware
ssss - 2 PCH Stack
Pointer
ssss - 1 PCL
-Hardware ssss
Stack
Pointer
Stack Stack
to FIRQ)
Figure 15-1. Saving the Limited Processor State in the Hardware Stack (Response
the limited state is saved after the recognition of FIRQ and Figure 15-2 shows
the order in which the entire state is saved after other inputs or instructions.
The E (Entire) flag distinguishes the two alternatives (E is 1 if the entire state
has been saved and if only the limited subset has been saved).
4. The CPU fetches an address from a specified pair of memory locations and
locations
loads that address into the Program Counter. Table 15-1 lists the
assigned to the various inputs and to the SWI instructions.
MSBs LSBs
SPECIAL FEATURES
Note the following features of the 6809 interrupt system:
1. The 6809 automatically saves the entire or limited state of the processor in
Interrupts 15-5
Before After
ssss - 12 cc Hardware
i
ssss - 1 aa Stack
Pointer
ssss - 10 bb
ssss - 9 dd
ssss - 8 XH
ssss - 7 XL
ssss - 6 YH
ssss - 5 YL
ssss - 4 UH
ssss - 3 UL
ssss - 2 PCH
ssss - 1 PCL
u j
Stack
Pointer
Stack Stack
aa = Contents of Accumulator A
bb = contents of Accumulator B
dd = Contents of Direct Page Register
XH = Index Register X high-order byte
XL = Index Register X low-order byte
YH = Index Register Y high-order byte
YL = Index Register Y low-order byte
UH = User Stack Pointer U high-order byte
UL = User Stack Pointer U low-order byte
PCH = Original contents of Program Counter high-order byte
PCL = Original contents of Program Counter low-order byte
Figure 15-2. Saving the Entire Processor State in the Hardware Stack
the Hardware Stack. The Program Counter is always saved so the inter-
rupted program can be resumed. The Condition Code Register (including the
Interrupt Mask and Fast Interrupt Mask flags) is always saved as well.
2. The Fast Interrupt Request not only provides a second maskable interrupt
input, but it also provides a faster response since only the Program Counter
and the Condition Code Register are saved. Saving only the limited state
reduces the response time by 9 clock cycles, since 1 clock cycle is needed to
transfer each byte to the Stack.
3. The 6809 provides external hardware signals (using the BUS AVAILA-
BLE and BUS STATE lines) to indicate that it has accepted an interrupt.
These lines can be used to activate external hardware.
4. The 6809 has no special internal provisions for determining the source of
an interrupt when there are several sources tied to the same input.
.
Interrupt-Related Instructions
The following special instructions can be used to manipulate the 6809 interrupt
system:
1. ANDCC #%11101111 (or CLI) clears bit 4 of the Condition Code Register
and thus enables the regular interrupt. ANDCC* %10111111 (or CLF)
similarly clears bit 6 of the Condition Code Register and thus enables the fast
interrupt. Of course, ANDCC #%10101111 (or CLIF) enables both inter-
rupts at once.
2. ORCC #%00010000 (or SEI) sets bit 4 of the Condition Code Register and
thus disables the regular interrupt. ORCC #%01000000 (or SEF) similarly
sets bit 6 of the Condition Code Register and thus disables the fast interrupt.
ORCC#%01010000 (or SEIF) disables both interrupts at once.
3. SWI (Software Interrupt) sets the Entire flag, saves all the user registers in
the Hardware Stack, and disables the regular and fast interrupts. It then places
the contents of addresses FFFA and FFFB in the Program Counter. SWI2
(Software Interrupt 2) and SWI3 (Software Interrupt 3) are similar, except
that theydo not affect the interrupt masks and they use different vector
addresses (FFF4 and FFF5 for SWI2, FFF2 and FFF3 for SWI3).
4. RTI (Return from Interrupt) restores the registers from the Hardware Stack
at the end of an interrupt service routine. If the recovered E flag is cleared,
RTI restores only the Condition Code Register and the Program Counter.
Thus RTI is similar to RTS, but RTI restores other registers as well as the
Program Counter.
5. CWAI (Clear and Wait for Interrupt) logically ANDs a byte of immediate
data with the Condition Code Register (usually enabling the regular or fast
interrupts) , saves all the user registers in the Hardware Stack, and waits for an
interrupt to occur. The response to the interrupt is rapid (9 clock cycles),
since the registers have already been saved. Note that, if a CWAI instruction
has been executed and a fast interrupt occurs, the CPU will enter the fast
interrupt service routine with all its registers saved (and with the E flag in the
Stack set)
6. SYNC (Synchronize to External Event) causes the processor to stop execut-
ing instructions. The CPU simply waits for an interrupt. If the interrupt is
masked or lasts less than 3 clock cycles, the CPU continues to the next
instruction without stacking registers or performing an interrupt service
routine. Otherwise, the CPU performs its normal interrupt response. SYNC
allows an extremely fast response to a single (presumably high-priority) inter-
rupt, since no stacking or vectoring is performed. Obviously, the use of SYNC
is a one-time only approach, since the CPU does not save its previous state or
identify the source. Figure 15-3 illustrates the use of the SYNC instruction in
this manner.
The SWI (Software Interrupt) instructions produce almost exactly the same
response as an interrupt signal (hence the name). The only difference is the locations
from which the CPU obtains the new value of the Program Counter. SWI instructions
are useful for debugging (see Chapter 19) and for returning control to a monitor or
operating system while simultaneously saving the current state in the stack. SWI
Interrupts 15-7
instructions are also referred to as traps, since they can be used to trap the microcom-
puter to special routines in the event of hardware errors or other unusual events. 3
SWI is commonly used in packaged monitors and operating systems to transfer control
from user to system; SWI2 is supposed to be available to the end user, and hence should
not be used in packaged systems software.
Fast Interrupt
The maskable interrupt. In response to it, the
fast interrupt is a high-priority
CPU clears the E and saves the Program Counter and Condition Code Register in
flag
the Hardware Stack (assuming that it is not executing a CWAI instruction). It then
obtains the new value for the Program Counter from memory addresses FFF6 and
FFF7. The differences between regular and fast interrupts are thus minimal from the
programmer's point of view and we will not refer to fast interrupts again.
Nonmaskable Interrupt
±
SYNC Wait for data byte available
I
Decrement Byte
Counter
vice routine. Nonmaskable interrupts are useful for applications that must respond to
loss of power (usually by saving data in a low-power memory or switching to a backup
battery). 4 Typical applications are communications equipment that must retain codes
and partially received messages, and test equipment that must keep track of partially
completed tests. We will not discuss the nonmaskabl e int errupt any further. Henceforth,
we will assume that- all interrupt inputs are tied to IRQ.
Bits 1 (control line 1) and 4 (control line 2) determine whether a rising edge (low-
to-high transition) or a falling edge (high-to-low transition) on the control line causes an
interrupt.
1. The PIA has interrupt enable bits, whereas the 6809 microprocessor has
interrupt mask flags. That is, the PIA bits must be T to allow interrupts,
while the microprocessor flags must be '0' to have the same effect.
1. The transmitter interrupt (signifying that the ACIA is ready for data) is
2. The receiver interrupt (signifying that the ACIA has received new data) is
Interrupts 1 5-9
4. The occurrence of either interrupt sets bit 7 of the Status Register. Either
reading data from the ACIA or writing data into the ACIA clears bit 7.
2. A
Check each 6850 ACIA by examining bit 7 of the Status Register:
Bit 7 of the ACIA Status Register indicates that either a receiver or a transmit-
ter interrupt has occurred. Bit will be set if a receiver interrupt has occurred
and bit 1 will be set if a transmitter interrupt has occurred. Of course, the
interrupt must be one or the other, so our program assumes a transmitter
interrupt if it does not find a receiver interrupt.
1. The order in which status bits are examined determines the priority of the
interrupts. Obviously, the CPU willproceed no further if it finds an active
it ignores activity
interrupt; thus from sources later in the sequence. Priorities
are easy to establish (merely by selecting the order of examination) but
difficult to change or vary.
2. The must clear a PIA interrupt by reading the correspond-
service routine
ing Data Register, even if the port is being used for output or no data
transfer is necessary. Otherwise, the interrupt will remain active. The pro-
grammer can use the TST (test zero or minus) instruction to read the PIA
Data Register without changing its contents or the contents of a User
Register.
Polling routines are adequate if the of sources is small and the frequency
number
of interrupts is low. If there are many sources or interrupts are frequent, polling
routines are slow and awkward for the following reasons.
15-10 6809 Assembly Language Programming
1. The average number of polling operations increases linearly with the num-
ber of inputs. On the average, of course, a polling routine will have to
examine half of the inputs before finding the active one. You can reduce the
average number of polling operations somewhat by checking the most fre-
quent inputs first.
2. PIA and ACIA addresses are rarely consecutive or evenly spaced; therefore,
separate instructions are necessary to examine each input. Polling routines
are therefore difficult to expand. You can use tables of I/O addresses,
accessed via one of the indexed addressing modes.
3. Interrupts that are polled early may shut out those that are polled later
unless the order of polling is varied. However, varying the order of polling is
difficult since the addresses are not consecutive.
1. They should not interfere with the normal execution of the main program.
2. They should not depend on how the main program operates. For example,
they should not require the main program to be inactive (i.e., executing
CWAI or SYNC) or assume that certain registers are always available.
3. They should be well-defined and capable of handling varied amounts of data.
4. They should not require instantaneous action by the main program. The more
patient the system is, the easier it will be to develop and maintain.
The idea is to make the service routines and the main program transparent to each
other. This approach allows the programmer to change one without affecting the other.
It also helps limit errors to one or the other, rather than to the connection between
them.
Interrupts 15-11
SOFTWARE HANDSHAKE
A simple approach to communications is a software "handshake," much like
the hardware handshake used in asynchronous input/output as described in Chapter
12. The provider of data (the interrupt service routine for input or the main program
for output) sets a flag to indicate that new data is available. The receiver or acceptor
of data can then examine that (sometimes called a semaphore) and can clear it
flag
after transferring (or accepting) the data. The receiver may itself set another flag (an
acknowledgment) to indicate that the most recent datas been processed and more can
be sent.
Where do we place the flags and the data? A simple approach is to use a single
memory location for each flag and for the data; the location can be a specific memory
address or an address in the Hardware Stack that has been set aside for that purpose.
The main program and the service routines then communicate through those locations,
much as the processor communicates with I/O devices through I/O ports.
BUFFERED INTERRUPTS
The approach outlined above assumes that we handle I/O on a byte-by-byte basis.
The processor must provide each output byte separately and must handle each input
byte separately. Clearly, all operations must proceed at a rate that is guaranteed to be
fast enough to avoid losing data. As with normal I/O, we can relax the time con-
straints by using buffers. In this approach, the service routine transfers data to or
from a buffer and updates the buffer pointer for the next operation. The only time the
main program has to be concerned is when an input buffer is full or an output buffer
is empty. The service routines act as I/O devices that have their own local memory in
which data can be stored temporarily. This approach is referred to as buffered interrupts.
Double Buffering
In fact, we can extend this approach. We can provide one buffer for the service
routine and a separate buffer for the main program. Now even the filling or emptying
of a buffer creates no problem as long as the other buffer is immediately available. In
fact,the identities of the buffers can simply be interchanged when the service routine
has filled or emptied its buffer. This approach is known as double buffering; it allows
interrupt-driven input/output to proceed in almost total independence of the main pro-
gram.
1. During the initialization of the interrupt system itself. This may involve
loading initial values into pointers, flags, and counters or determining an
initial order for polling or other operations. Remember that RESET automat-
ically disables the CPU and PIA interrupts, so the system startup routine will
have to explicitly enable them.
2. During the servicing of an interrupt. If interrupts are not disabled at least
until the current one is cleared, the computer will enter an endless loop with
the interrupt endlessly interrupting its own service routine. Remember that
the 6809 microprocessor automatically disables the regular interrupt as part of
its normal response. Note also that an NMI interrupt will not interfere with its
own service routine, since the input is edge-sensitive, rather than level-sensi-
tive.
3. During operations that occur in real time (such as delay loops or high-speed
synchronous I/O) or that could produce erroneous results if interrupted. A
typical example of the latter situation is the updating of multi-byte data that
the interrupt service routine must use, such as the calendar time or
geographical position. A partial update could produce a highly erroneous
value, such as a clock time that is off by an hour or a day because the interrupt
occurred before that part of the time was changed.
PIA INTERRUPTS
If you must disable a particular interrupt, you can disable it independently of
other interrupts by clearing the interrupt enable flag for a specific port of a particular
PIA. You can do this without affecting other control register bits by using logical opera-
tions.
Control line 2
LDA PIACR
ANDA #%1U101U DISABLE CONTROL LINE 2 INTERRUPT
STA PIACR
Control line 2
LDA PIACR
ORA #$00001000 ENABLE CONTROL LINE 2 INTERRUPT
STA PIACR
The INC and DEC instructions take advantage of the fact that bit is the interrupt
enable for control line 1. However, these instructions can affect the entire PIA control
register if they are inadvertently executed when the interrupt enable is already in the
desired state. Consider, for example, what would happeri if the CPU were to execute
DEC PIACR when bit of the control register was already 0. The INC and DEC instruc-
tions are thus less general, as well as more difficult for the casual reader to understand,
than the logical instructions.
I ndexed Offset
Register
(Hexadecimal)
Condition Code 00
Accumulator A 01
Accumulator B 02
Direct Page Register 03
High-Order Byte of Index Register X 04
Low-Order Byte of Index Register X 05
High-Order Byte of Index Register Y 06
Low-Order Byte of Index Register Y 07
High-Order Byte of User Stack Pointer U 08
Low-Order Byte of User Stack Pointer U 09
High-Order Byte of Program Counter OA
Low-Order Byte of Program Counter OB
Indexed Offset
Register (Hexadecimal)
Condition Code 00
High-Order Byte of Program Counter 01
Low-Order Byte of Program Counter 02
Table 15-2 contains the indexed offsets required to access the registers in the case
in which the processor has saved the e ntire st ate. Table 15-3 contains the indexed
offsets required in the case (in response to FIRQ) in which the processor has saved only
the program counter and the condition code register. Typical routines using the offsets
in Table 15-2 are:
Only if the LSB's of the return address are zero is it necessary to decrement
the MSB's in order to produce a correct 16-bit decrement.
3. Disabling the regular interrupt by setting the regular interrupt mask bit (bit
LDA ,S
ORA #%00010000 DISABLE REGULAR INTERRUPT
STA ,S
Interrupts 15-15
4. Disabling the fast interrupt by setting the fast interrupt mask bit (bit 6 of the
Condition Code Register):
LDA ,S
ORA #%01000000 DISABLE FAST INTERRUPT
STA ,S
Obviously, the programmer must be extremely careful when altering stack values,
since these changes could have unforeseen side effects in the main program.
INTERRUPT OVERHEAD
Responding some overhead cycles, since the CPU
to an interrupt always involves
may have new program counter value from memory and save registers in the
to fetch a
Hardware Stack. Of course, the restoring of registers from the Hardware Stack, if
necessary, also uses processor time. You can determine the amount of overhead
involved in servicing interrupts from the time requirements in Table 15-4.
Number of
Operation
Clock Cycles
Execution of CWAI 20
Execution of RTI with E flag set (Entire state) 15
Execution of RTI with E flag cleared (Limited state) 6
Execution of SWI 19
Execution of SWI2 or SWI3 20
Execution of SYNC 2
PROGRAM EXAMPLES
15-1. A STARTUP INTERRUPT
Purpose: The computer waits for a PIA interrupt to occur before starting actual opera-
tions.
Often a system remains inactive until the operator actually starts it or until a
DATA READY signal is received. On RESET, such a system must initialize the Stack
Pointer, enable the startup interrupt, and execute a halt (CWAI) or an endless loop or
jump-to-self instruction. Remember that RESET disables the processor interrupt (by
setting I and F both to 1) as well as all the PIA interrupts (by clearing all the PIA inter-
rupt enable bits) In the flowchart, the decision as to whether startup
. is active is made in
hardware (by the CPU examining the interrupt input internally) rather than in software.
15-16 6809 Assembly Language Programming
Program 15-1:
Main Program:
8001 PIACA EQU $8001
8000 PI ADA EQU $8000
0100 INTRP EQU $0100
*
0000 ORG $0000
0000 10CE 0100 LDS #$100 START STACK AT MEMORY LOCATION
* OOFF
0004 86 05 LDA #%00000101 ENABLE INTERRUPT FROM
0006 B7 8001 STA PIACA STARTUP PIA
0009 3C EF CWAI #%11101111 ENABLE REGULAR INTERRUPT
* AND WAIT
000B 3F SWI DUMMY CONTINUATION
Flowchart:
C Start
J
T
Initialize Stack
Pointer
Enable startup
interrupt on PIA
Enable CPU interrupt
The exact location (INTRP) of the interrupt service routine varies with the
microcomputer. If your microcomputer has no monitor, you can simply place whatever
address you want in memory locations FFF8 and FFF9 (or whatever locations respond
to those addresses). You must then start the interrupt service routine at the address you
chose. Of course, you should locate the routine so it does not interfere with fixed
addresses or with other programs.
Program Operation
The main program's only action is to enable the interrupt from the startup PIA.
The program enables that interrupt by setting bit of thePIA Control Register before
enabling the CPU interrupt. Note that we must set the PIA interrupt enable and clear
the CPU interrupt mask bit.
The CWAI instruction logically ANDs the Condition Code Register with the
following byte of immediate data before halting instruction execution. Logically AND-
ing the Condition Code Register with 1 1 101 1 1 2 clears bit 4 of the Condition Code
Register, thus enabling the regular interrupt. Similarly, logically ANDing with
101 1 1 11 2
would clear bit 6 of the Condition Code Register, thus enabling the fast inter-
rupt. Logically ANDing with 10101 1 1 2
would enable both maskable interrupts.
CWAI causes the 6809 CPU to save all its registers in the Hardware Stack and wait
for an interrupt to occur.
In response to an interrupt (IRQ) the CPU disables IRQ and transfers control to
,
the address in memory locations FFF8 and FFF9. (Remember that all the registers have
already been saved in the Hardware Stack.)
The service routine clears the startup interrupt by reading the appropriate PIA
Data Register. This operation is necessary, even though no data transfer is required.
Otherwise, the startup interrupt would remain active and would interrupt again as soon
as the CPU interrupt was reenabled.
RTI restores all the user registers from the Hardware Stack, thus reenabling the
CPU interrupt (since the old flag is restored) and transferring control to the instruction
immediately following CWAI. Note that transferring control to the service routine does
not change the contents of the user registers, but RTI does. The LDA instruction in the
service routine affects Accumulator A and the Condition Code Register, but those
effects are lost when RTI is executed.
Sample Problem:
Keyboard data = 43
Result: (0040) = 01 Flag indicating new keyboard data
(0041) = 43 Keyboard data
15-18 6809 Assembly Language Programming
Program 15-2a:
Main Program :
Flowchart:
Main Program:
c Start
J
I
Initialize Stack
Pointer
Data Ready Flag =
Enable keyboard
interrupt on PIA
Enable CPU interrupt
C Start
J
(0041)
= Keyboard Data
c End
D
Interrupts 15-19
You must initialize the PIA completely before enabling interrupts. This includes
establishing the directions of ports and control lines and determining the transitions to
be recognized on input strobes.
The main program clears the Data Ready Flag (memory location 0040) and then
simply waits for the interrupt service routine to set it. The main program and the service
Program 15-2b:
Main Program:
8001 PIACA EQU $8001
8000 PI ADDA EQU $8000
8000 PI ADA EQU $8000
0100 INTRP EQU $0100
OOOD CR EQU $0D
it
This program fills a buffer starting at memory location 0050 until it receives a car-
riage return character (CR). Memory locations 0041 and 0042 hold the current buffer
pointer. The interrupt service routine increments that pointer (with autoincrementing)
after each use.
In a real application, the CPU could perform other tasks between interrupts. It
could, for example, edit, move, or transmit a line from one buffer while the interrupt
was filling another buffer. This is the double buffering approach. The main program only
has to ensure that no buffers ever overflow.
An alternative approach would be for memory location 0040 to contain a
counter rather than a flag. The contents of that location would then indicate to the
main program how many bytes of data had been received. The main program could then
deal with the buffer a certain number of new data bytes were in it. The service
whenever
routine would simply increment the counter as well as the buffer pointer as part of each
input operation.
Sample Problem:
(0041) = 51
Result: (0040) = 01 Flag indicating last data item has been sent
Printer receives a 5 1
(ASCII Q) when it is ready.
Program 15-3a:
Main Program :
Flowchart:
Main Program:
f Start
J
Initialize
7Hardware
Stack Pointer
Data Accepted Flag
=
Enable printer
interrupt on PIA
Data = (0041)
Enable CPU interrupt
15-22 6809 Assembly Language Programming
C Start
D
Data Accepted Flag
= 1
c End
}
The only differences from the keyboard interrupt routines are the meaning of the
flag, the direction of the data transfer, and the need for the dummy LDA
instruction
PIADB to clear bit 7 of the PI A Control Register. Remember that an input operation au-
tomatically clears that bit, but an output operation does not.
Here the memory location 0040 indicates that the CPU has data available
flag in
been sent to the printer. When the interrupt service routine sets the flag,
that has not yet
the main program knows the data has been sent. The flag acts as an acknowledgement
from the printer or a Data Accepted indicator.
Remember that you may find it necessary to place a dummy read at the start of the
main program to clear stray interrupts. LDA PIADB or TST PIADB will do the job, as
long as you place it after the instruction that addresses the data register but before the
instruction that enables CPU interrupts.
Program 15-3b:
in Program
8003 PIACB EQU $8003
8002 PIADDB EQU $8002
8002 PIADB EQU $8002
0100 INTRP EQU $0100
000D CR EQU $0D
it
We could use double buffering to allow I/O and processing to occur independently
without ever halting the CPU.
Fixed-Length Buffer
Still another approach uses memory location 0040 as a buffer counter. For
example, the following program waits for 20 characters to be sent to the printer.
Program 15-3c:
Main Program:
8003 PIACB EQU $8003
8002 PIADDB EQU $8002
8002 PIADB EQU $8002
0100 INTRP EQU $0100
it
Real-Time Clock
A real-time clock simply provides a regular series of pulses. The interval be-
tween the pulses can be used as a time reference. Real-time clock interrupts can be
counted to give any multiple of the basic time interval. A real-time clock can be pro-
duced by dividing down the CPU clock, by using a timer like the 6840 device or the one
included in the 6846 multifunction support device, or by using external sources such as
the AC line frequency.
Note the tradeoffs involved in determining the frequency of the real-time clock.
A high frequency (say 10 kHz) allows the creation of a wide range of time intervals of
high accuracy. On the other hand, the overhead involved in counting real-time clock
interrupts may be considerable, and the counts will quickly exceed the capacity of a
single 8-bit register or memory location. The choice of frequency depends on the preci-
sion and timing requirements of your application. The clock may, of course, consist
partly of hardware; a counter may count high frequency pulses and interrupt the pro-
cessor only occasionally. A program will have to read the counter to measure time to
high accuracy.
One problem is synchronizing operations with the real-time clock.Clearly, there
be some effect on the precision of the timing interval if the CPU starts the measure-
will
ment randomly during a clock period, rather than exactly at the beginning. Some ways
to synchronize operations are:
1. Start the CPU and clock together. RESET or a startup interrupt can start the
clock as well as the CPU.
2. Allow the CPU to start and stop the clock under program control.
3. Use a high-frequency clock so that an error of less than one clock period will
be small.
4. Line up the clock (by waiting for an edge or interrupt) before starting the
measurement.
A real-time clock interrupt should have very high priority, since the precision of
the timing intervals will be affected by any delay in servicing the interrupt. The usual
practice is to make the real-time clock the highest priority interrupt except for power
failure. The clock interrupt service routine is generally kept extremely short so that it
Program 15-4a:
Main Program:
8001 PIACA EQU $8001
8000 PIADA EQU $8000
0100 INTRP EQU $0100
*
0000 ORG $0000
0000 10CE 0100 LDS #$100 START STACK AT MEMORY LOCATION
* 00FF
0004 OF 40 CLR $40 CLEAR CLOCK COUNTER TO START
0006 86 05 LDA #%00000101 ENABLE REAL-TIME CLOCK
0008 B7 8001 STA PIACA INTERRUPT
000B 1C EF ANDCC #%11101111 ENABLE CPU INTERRUPT
000D 0D 40 WTCLK TST $40 HAS CLOCK BEEN INCREMENTED?
000F 27 FC BEQ WTCLK NO, WAIT
0011 3F SWI YES, PROCEED
Interrupts 15-25
edge of the clock. If that bit is 1, the interrupt will occur on the low-to-high (ris-
(falling)
ing) edge of the clock.
The interrupt service routine must explicitly clear bit 7 of the PIA Control
Register since no data transfer is necessary.
You could use the PIA data port as long as you did not accidentally clear the
still
status bit from the real-time clock before it was recognized. This would be no problem if
the port were used for output to a simple peripheral (such as a set of LEDs) , since out-
put operations do not affect the status bits anyway.
Clearly, we can easily extend this routine to handle more counts and provide
greater precision by using more memory locations for the clock counter and a different
test in the main program.
Main Program:
8001 PIACA EQU $8001
8000 PI ADA EQU $8000
0100 INTRP EQU $0100
*
0000 ORG $0000
0000 10CE 0100 LDS #$100 START STACK AT MEMORY LOCATION
00FF
0004 OF 40 CLR $40 CLEAR CLOCK COUNTER TO START
0006 86 05 LDA #%00000101 ENABLE REAL-TIME CLOCK
0008 B7 8001 STA PIACA INTERRUPT
000B 1C EF ANDCC #%11101111 ENABLE CPU INTERRUPT
000D 86 0A LDA #10 TARGET COUNT = 10
000F 91 40 WTCNT CM PA $40 HAS CLOCK COUNTER REACHED TARGET
COUNT?
0011 26 FC BNE WTCNT NO, WAIT
0013 3F SWI
We assume that a 100 Hz input clock provides the regular source of interrupts.
Flowchart:
C~~ Start
~J
T
Clear clock interrupt
Hundredths =
Hundredths + 1
Hundredths =
Seconds =
Seconds + 1
Seconds =
Minutes =
Minutes + 1
c End
Z>
.
Interrupts 15-27
Program 15-4c:
Now we could produce a delay of 300 ms in the main program with the routine:
This approach is the same one you would take if you had to let something cook for
20 minutes. You must determine the current time by reading your watch (the counter),
calculate the target time by adding 20 (mod 60, so 20 minutes past 6:50 is 7:10), and wait
for your watch to reach the target time. Change the program so it produces a 20 minute
delay (an obvious requirement for a microprocessor-controlled microwave oven)
Of course, the program could perform other tasks and only check the elapsed time
occasionally. How would you produce a delay of seven seconds? Of three minutes?
Many applications do not require long delays to be highly accurate; for example, the
operator of a microwave oven does not care if the time intervals are off by a few seconds.
Sometimes you may want to keep time either as BCD digits or as ASCII charac-
ters. How would you revise the last interrupt service routine to handle these alterna-
tives?
actually uses very little processor time. The execution times are as follows :
Much of the execution time (see Table 15-4) goes to the interrupt response (21
clock cycles) and to the RTI instruction (15 clock cycles), since these require the
transfer of many registers to and from the Hardware Stack. Thus the largest number of
clock cycles ever used by the real-time clock service routine 118 during a total period
is
of 10 milliseconds. This is 1.18% of the available processor time if the clock frequency is
1 MHz. The average requirement is half the maximum, since the service routine
requires its minimum execution time 99 times out of 100 and only requires its max-
imum execution time once every 360,000 times (once per hour). Thus a real-time clock
generally does not burden the processor very much, unless its frequency is high.
High-Frequency Clock
Even a high-frequency real-time clock can be handled without much processor
intervention. The usual method is to have the clock increment a set of counters which
then interrupt the processor at a much lower frequency. For example, the input fre-
quency could be 1 MHz; that input frequency would then be passed through 3 decimal
counters and the output of the last one would be tied to the PI A. The PI A would receive
a single clock pulse for every 1000 input pulses (that is, when the 3 decimal counters
overflow). The processor can determine the time to greater precision than 1 ms by read-
ing the counters, since they contain the less significant digits. As usual, some additional
hardware (counters and input ports) is necessary to reduce the burden on the CPU. This
is a typical tradeoff; the additional hardware is worthwhile only if the application
requires precise timing.
Purpose: The main program clears a flag in memory location 0040 and waits for an
interrupt from a 6850 ACIA. The interrupt service routine sets the flag in
memory location 0040 to 1 and places the data from the ACIA in memory
location 0041. The characters are 7-bits in length with odd parity and two stop
bits.
Program 15-5a :
Main Program:
Since the 6850 ACIA has no RESET input, a MASTER RESET (setting Control
register bits and 1 to one simultaneously) is necessary before the ACIA is initialized.
We then initialize the bits in the ACIA control register as follows:
Purpose: The main program clears a flag in memory location 0040 and waits for a
teletypewriter interrupt. The interrupt service routine sets the flag in memory
location 0040 to 1 and places the data from the teletypewriter in memory loca-
tion 0041.
Program 15-5b :
Main Program:
transition in the character will cause an interrupt. Note that reading the data bits will
clear any status flags set by the ignored transitions. Of course, the program must reena-
ble the PI A interrupt (by setting bit of the control register) to alldw receipt of the next
character, but this should be done after the current character has been read.
As we mentioned earlier in this chapter, we can also disable PIA interrupts by
using logical functions or the INC and DEC instructions. The following programs are
independent of the contents of the PIA Control Register.
LDA PIACR
ANDA #%11111110 DISABLE PIA IMTERRUPT
STA PIACR
LDA PIACR
ORA #%00000001 ENABLE PIA INTERRUPT
STA PIACR
The DEC instruction only works correctly if you know that the interrupt is
enabled, while the INC instruction only works correctly if you know that the interrupt is
disabled. If the interrupt is already in the desired state, INC or DEC can have curious
effects (try it!), whereas the logical functions have no effect in that case.
1. Saving any needed data in the Stack so the interrupted program can be
resumed correctly. The 6809 mi croprocessor saves all the user registers auto-
matically in response to IRQ or NMI and as part of the execution of CWAI
and the Software Interrupt instructions. An interrupt service routine for
Interrupts 15-31
FIRQ will have to save and restore any registers it uses besides the Program
Counter and the Condition Code Register.
2. Restoring data and registers (if not automatically saved) before executing
RTI and returning control to the interrupted program.
3. Establishing the priority of the interrupt, perhaps by writing that priority
into an external register.
The program can then reenable the of the interrupt system. Remember,
rest
however, that to restore the old you must save it in the
priority correctly,
stack along with the other status. The program must save a copy of the current
priority in RAM if the external priority register is write-only.
4. Restoring the old priority before returning control to the interrupted pro-
gram.
5. Enabling and disabling interrupts appropriately. Remember that the CPU
automatically disablesIRQ after accepting an interrupt on that line a nd au to-
matically disables IRQ and FIRQ after accepting an interrupt on FIRQ or
NMT.
The service routines should be transparent as far as the interrupted program is
concerned; that is, they should have no incidental effects.
Any standard subroutines that an interrupt service routine uses must be
reentrant. If some subroutines cannot be made reentrant, the interrupt service routine
must have separate versions to use.
PROBLEMS
15-1. A TEST INTERRUPT
Purpose: The computer waits for a PIA interrupt to occur, then executes the endless
loop instruction:
Sample Problem:
REFERENCES
1. A. Osborne. An Introduction to Microcomputers: Volume 1 — Basic Concepts,
Osborne/McGraw-Hill, Berkeley, Calif., 1980, Chapter 5.
2. R. L. Baldridge. "Interrupts Add Power, Complexity to Microcomputer Software
Design," EDN, August 5, 1977, pp. 67-73.
3. R. Morris. "6800 Routine Supervises Service Requests," EDN, October 5, 1979,
pp. 73-81.
4. I. P. Breikss. "Nonmaskable Interrupt Saves Processor Register Contents,"
Electronics, July 21, 1977, p. 104.
The previous chapters have described how to write short assembly language pro-
grams. While this an important topic, it is only a small part of software development.
is
Although writing assembly language programs is a major task for the beginner, it soon
becomes simple. By now you should be familiar with standard methods for program-
ming in assembly language on the 6809 microprocessor. The next six chapters will de-
scribe how to formulate tasks as programs and how to combine short programs to
form a working system.
• Problem definition
• Program design
• Coding
• Debugging
• Testing
• Documentation
• Maintenance and redesign
C Start
J
I*
Problem definition Coding and
and documentation documentation
3
Program design Debugging
and documentation
Design
evaluation
Final
documentation
Maintenance
and redesign
End
C )
Problem Definition
Problem definition is the formulation of the requirements that the task places
on the computer. For example, what is necessary to make a computer control a tool, run
a series of electrical tests, or handle communications between a central controller and a
remote instrument? Problem definition requires that you determine the forms and rates
of inputs and outputs, the amount and speed of processing that is needed, and the types
of possible errors and their handling. Problem definition takes a vague idea of building a
computer-controlled system and defines the tasks and requirements for the computer.
Program Design
Program design is the outline of the computer program that will meet the
requirements. In the design stage, the tasks are described in a way that can easily be
converted into a program. Among the useful techniques in this stage are flowcharting,
structured programming, modular programming, and top-down design.
Coding
Coding is the writing of the program in a form that the computer can either
directly understand or translate. The form may be machine language, assembly
language, or a high-level language.
IV-4. 6809 Assembly Language Programming
Debugging
Debugging, also called program verification, is making the program perform
according to the design. In this stage, you use such tools as breakpoints, traces, simula-
tors, logic analyzers, and in-circuit emulators. The end of the debugging stage is hard to
define, since you never know when you have found the last error.
Testing
Testing, also referred to as program validation, is ensuring that the program per-
forms the overall system tasks correctly. The designer uses simulators, exercisers, and
statistical techniques to measure the program's performance. This stage is like quality
Documentation
Documentation is the description of the program in the proper form for users
and maintenance personnel. Documentation also allows the designer to develop a pro-
gram library so that subsequent tasks will be far simpler. Flowcharts, comments,
memory maps, and library forms are some of the tools used in documentation.
INPUTS
How do we start the definition? The obvious place to begin is with the inputs. We
should begin by listing all the inputs that the computer may receive in this applica-
tion.
Examples of inputs are:
1. What is its form; that is, what signals will the computer actually receive?
2. When is the input available and how does the processor know it is available?
Does the processor have to request the input with a strobe signal? Does the
input provide its own clock?
4. How often does it change, and how does the processor know that it has
changed?
5. Does the input consist of a sequence or block of data? Is the order important?
6. What should be done if the data contains errors? These may include transmis-
sion errors, incorrect data, sequencing errors, extra data, etc.
7. Is the input related to other inputs or outputs?
OUTPUTS
The next step to define is the output. We must list all the outputs that the com-
puter must produce. Examples of outputs include:
1. What is its form; that is, what signals must the computer produce?
2. When must it be available, and how does the peripheral know it is available?
3. How long must it be available?
4. How often must it change, and how does the peripheral know that it has
changed?
5. Is there a sequence of outputs?
6. What should be done to avoid transmission errors or to sense and recover
from peripheral failures?
PROCESSING SECTION
Between the reading of input data and the sending of output results is the process-
ing section. Here we must determine exactly how the computer must process the input
data. The questions are:
1 What is the basic procedure (algorithm) for transforming input data into out-
put results?
2. What time constraints exist? These may include data rates.
3. What memory constraints exist? Do we have limits on the amount of program
memory or data memory, or on the size of buffers?
4. What standard programs or tables must be used? What are their require-
ments?
5. What special cases exist, and how should the program handle them?
6. How accurate must the results be?
7. How should the program handle processing errors or special conditions such
as overflow, underflow, or loss of significance?
Problem Definition 16-3
ERROR HANDLING
An important factor in many applications is the handling of errors. Clearly, the
designer must make provisions for recovering from common errors and for diagnosing
malfunctions. Among the questions that the designer must ask at the definition stage
are:
3. Which errors will not be immediately obvious to the system? A special prob-
lem is the occurrence of errors that the system or operator may not recognize
as incorrect.
4. How can the system recover from errors with a minimum loss of time and
data and yet be aware that an error has occurred?
5. Which errors or malfunctions cause the same system behavior? How can
these errors or malfunctions be distinguished for diagnostic purposes?
6. Which errors involve special system procedures? For example, do parity
Another question is: How can the field technician systematically find the source of
malfunctions without being an expert? Built-in test programs, special diagnostics, or sig-
nature analysis can help. 1
11. Can the operator always determine or reset the state of the system after
interruptions or distractions?
16-4 6809 Assembly Language Programming
Building a system for people to use is difficult. The microprocessor can make the
system more powerful, more flexible, and more responsive. However, the designer still
must add the human touches that can greatly increase the usefulness and attractive-
ness of the system and the productivity of the human operator. 2
EXAMPLES
DEFINING A SWITCH AND LIGHT SYSTEM
Figure 16-1 shows a simple system in which the input is from a single SPST
switch and the output is to a single LED display. In response to a switch closure, the
processor turns the display on for one second. This system should be easy to define.
Switch Input
Let us first examine the input and answer each of the questions previously pre-
sented:
1. The input is a single bit, which may be either '0' (switch closed) or '1' (switch
open).
2. The input is always available and need not be requested.
3. The input is available for at least several milliseconds after the closure.
4. The input will seldom change more than once every few seconds. The pro-
cessor has to handle only the bounce in the switch. The processor must moni-
tor the switch to determine when it is closed.
+ 5 v
Input
Port ^L
+ 5 V
CPU
%d Output
Port
-@-J
The switch input is a '1' if the switch is open, '0' if the switch is closed.
The CPU applies the output to the cathode of the LED: a '0' lights the display.
Light Output
The next requirement in defining the system is to examine the output. The
answers to our questions are:
1. The output is a single bit, which is '0' to turn the display on, T to turn it off.
2. There are no time constraints on the output. The peripheral does not need to
be informed of the availability of data.
3 If the display is an LED, the data need be available for only a few milliseconds
at a pulse rate of about 100 times per second. The observer will see a con-
tinuously lit display.
Processing
The processing section is extremely simple. As soon as the switch input
becomes a logic '0', the CPU turns the light on (a logic '0') for one second. No time or
memory constraints exist.
Error Handling
Let us now look at the possible errors and malfunctions. These are:
Surely the first error is the most likely. The simplest solution is for the processor
to ignore switch closures until one second has elapsed. This brief unresponsive period
will hardly be noticeable to the human operator. Furthermore, ignoring the switch dur-
ing this period means thatno debouncing circuitry or software is necessary, since the
system will not react to the bounce anyway.
Clearly, the last three failures can produce unpredictable results. The display may
stay on, stay off, or change state randomly. Some possible ways to isolate the failures
would be:
• Lamp-test hardware to check the display; i.e., a button that turns the light on
independently of the processor
• A direct connection to the switch to check its operation
• A diagnostic program that exercises the input and output circuits
If both the display and switch are working, the computer is at fault. A field techni-
cian with proper equipment can determine the cause of the failure.
the value of the last completed entry from the data switches; eight LEDs are used for
the display.
The system will also, of course, require resistors, buffers, and drivers.
Inputs
The characteristics of the switches are the same as in the previous example. To
simplify the debouncing procedure and force the operator to release the buttons, we
have the system respond only after a button is released; this is a common technique
that reduces wear on the switches as well, since the operator is less tempted to press a
button repeatedly. In this system there is a distinct sequence of inputs, as follows:
1 The operator must set the data switches according to the eight most significant
bits of an address, then
2. press and release the High Address button. The high address bits will appear
on the lights, and the program will interpret the data as the high byte of the
address.
3. Then the operator must set the data switches with the value of the least sig-
nificant byte of the address and
4. press and release the low Address button. The low address bits will appear on
the lights, and the program will consider the data to be the low byte of the
address.
5. Finally, the operator must set the desired data into the data switches and
6. press and release the Data button. The display will now show the data, and the
program stores the data in memory at the previously entered address.
o
Data Switches
^o-
<So
o<>
Input <s*
Port
DPORT -o^o-
•o^o
Data
Bus
o^>
^
High Address
-o o
Input
Low Address
CPU Port -O O-
CPORT
-O OData
+ 5 V
-W*—
%t <>
% (Q) VSrV^>
-WV
**^>
—
[$
Output
Port
^% (Q)
wv
-vw—
.
<>
-^
<»
^ -vw-<»
-WSr
The operator may repeat the process to enter an entire program. Clearly, even in
this simplified situation, we will have many possible sequences to consider. How do we
cope with erroneous sequences and make the system easy to use?
Output
Output is no problem. After each input, the program sends to the displays the
complement (since the displays are active-low) of the input bits. The output data
remains the same until the next input operation.
Processing
The processing section remains quite simple. There are no time or memory con-
straints. The program can debounce the switches by waiting for a few milliseconds, and
must provide complemented data to the displays.
Error Handling
The system must be able to handle these problems in a reasonable way, since they
are certain to occur in actual operation.
The designer must also consider the effects of equipment failure. Just as before,
the possible difficulties are:
• Switch failure
• Display failure
• Computer failure
In this system, however, we must pay more attention to how these failures affect
the system. A computer failure will cause a complete system breakdown that will be easy
to detect. A display failure may not be immediately noticeable; here a Lamp Test feature
will allow the operator to check the operation. Note that we would like to test each LED
separately, in order to diagnose the case in which output lines are shorted together. In
addition, the operator may not immediately detect switch failure; however, the operator
should soon notice it and establish which switch is faulty by a process of elimination.
• Erroneous data
• Wrong order of entries or switches
• Trying to go on to the next entry without completing the current one
Problem Definition 16-9
The operator will presumably notice erroneous data as soon as it appears on the
displays. What is a viable recovery procedure? Some options are:
1 The operator must complete the entry procedure; i.e., enter Low Address and
Data if the error occurs in the High Address. Clearly, this procedure is waste-
ful and annoying.
2. The operator may restart the entry process by returning to the high address
entry steps. This solution is useful if the error was in the High Address, but
forces the operator to re-enter earlier data if the error was in the Low Address
or Data stage.
3. The operator may enter any part of the sequence at any time simply by setting
the Data switches with the desired data and pressing the corresponding but-
ton. This procedure allows the operator to make corrections at any point in the
sequence.
This type of procedure should always be preferred over one that does not allow
immediate error correction, has a variety of concluding steps, or enters data into the
system without allowing the operator a final check. Any added complication in hard-
ware or software will be justified in increased operator efficiency. You should always
prefer to let the microcomputer do the tedious work and recognize arbitrary sequences;
it never gets tired and never forgets the operating procedures.
A further helpful feature would be status lights that would define the meaning
of the display. Three status lights, marked "High Address," "Low Address," and
"Data," would let the operator know what had been entered without having to remem-
ber which button was pressed. The processor would have to monitor the sequence, but
the added complication in software would simplify the operator's task. Clearly, three
separate sets of displays plus the ability to examine a memory location would be even
more helpful to the operator.
We should note that, although we have emphasized human interaction,
machine or system interaction has many of the same characteristics. The
microprocessor should do the work. If complicating the microprocessor's task makes
error recovery simple and the causes of failure obvious, the entire system will work
better and be easier to maintain. Note that you should not wait until after the software
has been completed to consider system use and maintenance; instead, you should
include these factors in the problem definition stage.
Display
^> Output Port(s) _J Display
- Data Strobe
RCV
Input Port
c "2 From Central Computer
I 1 I I 2 I I 3 I
|
4 || . || . cl «r|
||
1 7 II 8 1 9 II SEND
1 ° 1
READY BUSY
D
I—/ 1— 1
mOO O O
O O 1—O 1—O O /— /—
1 O i
/""/ /"""/ r~i /
The display consists of ten 7 -segment displays, which may be multiplexed, controlled by a shift
register, or addressed separately. Two additional lights, READY and BUSY, are also present.
Inputs
Let us first look at the keyboard input. This is, of course, different from the
switch input, since the CPU must have some way of distinguishing new data. We will
assume that each key closure provides a unique hexadecimal code (we can code each
of the 12 keys into one digit) and a strobe. The program will have to recognize the
strobe and fetch the hexadecimal number that identifies the key. There is a time con-
straint, since the program cannot miss any data or strobes. The constraint is not serious,
since keyboard entries will be at least several milliseconds apart.
The transmission inputsimilarly consists of a series of characters, each iden-
tifiedby a strobe (perhaps from a UART) The program will have to recognize each
.
strobe and fetch the character. The data being sent across the transmission lines is
usually organized into messages. A possible message format is:
The terminal
will check the header, read the destination address, and see if the
message intended for it. If the message is for the terminal, the terminal accepts the
is
data. The address could be (and often is) hard- wired into the terminal so that the ter-
minal receives only messages intended for it. This approach simplifies the software at
the cost of some flexibility.
Outputs
The output is also more complex than in the earlier examples. If the displays are
multiplexed, the processor must not only send the data to the display port but must
also direct the data to a particular display. We will need either a separate control port
or a counter and decoder to handle this. Note that hardware blanking controls can blank
leading zeros as long as the first digit in a multi-digit number is never zero. Software can
also handle this task. Time constraints include the pulse length and frequency required
to produce a continuous display for the operator.
16-12 6809 Assembly Language Programming
• Header
• Terminal address
• Credit card number
• Trailer
A central communication computer may poll the terminals, checking for data
ready to be sent.
Processing
The processing in this system involves many new tasks, such as:
• Identifying the control keys by number and performing the proper actions
• Adding the header, terminal address, and trailer to the outgoing message
• Recognizing the header and trailer in the returning message
• Checking the incoming terminal address
Note that none of the tasks involves any complex arithmetic or any serious time
or memory constraints.
Error Handling
The number of possible errors in this system is, of course, much larger than in
the earlier examples. Let us first consider the possible operator errors. These include:
Some of these errors can be handled easily by organizing the program correctly.
For example, the program should not accept the Send key until the credit card number
has been completely entered, and it should ignore any additional keyboard entries until
the response comes back from the central computer. Note that the operator will know
that the entry has not been sent, since the Busy light will not go on. The operator will
also know when the keyboard has been locked out (the program is ignoring keyboard
entries) since entries will not appear on the display and the Ready light will be off.
,
recognizes the error late in the procedure. The operator should be able to correct errors
immediately and have few keys as possible. The operator will, however,
to repeat as
make a certain number of errors without recognizing them. Most credit card numbers
include a self-checking digit; the terminal could check the number before permitting
it to be sent to the central computer. This step would save the central computer from
The data transmission will probably have to include error checking and correct-
ing procedures. Some possibilities are:
2. Short messages may use more elaborate schemes. For example, the yes/no
response to the terminal could be coded to provide error detection and correc-
tion capability.
will not accept entries while a verification is in progress. The terminal may also unlock
after a certain maximum time delay. Certain entries could be reserved for diag-
nostics; i.e., certain credit card numbers could be used to check the internal operation
of the terminal and test the displays.
16-14 6809 Assembly Language Programming
REVIEW
Problem definition is as important a part of software development as it is of any
other engineering task. Note that it does not require any programming or knowledge of
the computer; rather, it is based on an understanding of the system and sound engineer-
ing judgment. Microprocessors offer flexibility and local intelligence that the designer
can use to provide a wide range of features.
Problem definition is independent of any particular computer, computer
language, or development system. It should, however, provide guidelines as to what
type or speed of computer the application will require and what kind of hardware/
software tradeoffs the designer can make. The problem definition stage should not
even depend on whether a computer is used, although a knowledge of the capabilities
of the computer can help the designer in suggesting possible implementations of pro-
cedures.
REFERENCES
D. R. Ballard. "Designing Fail-Safe Microprocessor Systems," Electronics, January
4, 1979, pp. 139-43.
BASIC PRINCIPLES
All the methodologies are based on common principles, many of which apply to
any kind of design. Among these principles are:
3. Keep the flow of control simple to make programs easy to follow and errors
easy to locate and correct.
4. Use pictorial or graphic design descriptions as much as possible. They are
easier to visualize than word descriptions. This is the great advantage of
flowcharts.
17-2 6809 Assembly Language Programming
5. Emphasize clarity and simplicity at first. You can improve performance (if
FLOWCHARTING
Flowcharting is best-known of all program design methods. Program-
certainly the
ming textbooks describe how programmers first write complete flowcharts and then
start writing the actual program. In fact, few programmers have ever worked this way,
and flowcharting has often been more of a joke or a nuisance to programmers than a
design method. We will try to describe both the advantages and disadvantages of
flowcharts, and show the place of this technique in program design.
ADVANTAGES OF FLOWCHARTING
The basic advantage of the flowchart is that it is a pictorial representation. Peo-
ple find such representations much more meaningful than written descriptions. The
designer can visualize the whole system and see the relationships of the various parts.
Logical errors and inconsistencies often stand out instead of being hidden in a printed
page. At its best, the flowchart is a picture of the entire system.
1. Standard symbols exist (see Figure 17-1) so that flowcharting forms are
widely recognized.
Program Design 17-3
^7 Input/output
Processing operation
(Arithmetic, Logic. Data movement)
Decision logic
CD Subroutine
o Connector point
J Connector arrows
DISADVANTAGES OF FLOWCHARTING
These advantages are all important. There is no question that flowcharting will
continue to be widely used. But we should note some disadvantages of flowcharting as
a program design method:
1. Flowcharts are difficult to design, draw, or change in all except the simplest
situations.
17-4 6809 Assembly Language Programming
4. Flowcharts show only the program organization. They do not show the
organization of the data or the structure of the input/output modules.
5. Flowcharts do not help with hardware or timing problems or give hints as to
where these problems might occur.
6. Flowcharts allow unstructured design. There are no rules governing the num-
number or type of interconnections, or the logic
bers of entries and exits, the
that may be employed.
EXAMPLES
Flowcharting the Switch and Light System
This simple task, in which a single switch turns on a light for one second, is
easy to flowchart. In fact, such tasks are typical examples for flowcharting books,
although they form a small part of most systems. The data structure here is so simple
that it can be safely ignored.
Figure 17-2 is the flowchart. There is little difficulty in deciding on the amount of
detail required. The flowchart gives a straightforward picture of the procedure, which
anyone could understand.
Program Design 17-5
Turn light on
c End
J
Figure 1 7-2. Flowchart of One-Second Response to a Switch
r Start
)
)
^^^Tow^^^
^^ Address
No ^^ Address ^^ No ^S^ Data N.No
^*w button ^ ^V. button y/^ >w ? ^^ i
t
Lights = Lights = Lights =
Switches Switches Switches
Store Data
in Address
< '
^ '
^ 1
Wait
debounce time
Let us look at some of the sections. Figure 17-4 shows the keyboard entry pro-
cess for the digit keys. The program must fetch the data after each strobe and place the
digit into the display array if there is room for it. If there are already ten digits in the
array, the program simply ignores the entry.
The actual program will have to handle the displays at the same time. Note that
either software or hardware must de-activate the keyboard strobe after the processor
reads a digit.
Program Design 17-7
C Start
J
Yes
Key Keyboard
Input Data
c End
J
(Key Pointer) = Key
Key Pointer
Key Pointer + 1
Key Counter
Key Counter + 1
Figure 17-5 adds the Send key. This key, of course, is optional. The terminal
could just send the data as soon as the operator enters a complete number. However,
that procedure would not give the operator a chance to check the entire entry. The
flowchart with the Send key is more complex because there are two alternatives.
1. Ifthe operator has not entered ten digits, the program must ignore the Send
key and place any other key into the entry.
2. Ifthe operator has entered ten digits, the program must respond to the Send
key by transferring control to the Send routine; and ignore all other keys.
Note that the flowchart has become much more difficult to organize and to follow.
There is also no obvious way to check the flowchart.
Figure 17-6 shows the flowchart of the keyboard entry process with all the func-
tion keys. In this example, the flow of control is not simple. Clearly, some written
description is necessary. The organization and layout of complex flowcharts requires
careful planning. We have followed the process of adding features to the flowchart one
at a time, but this still results in a large amount of redrawing. Again we should remem-
ber that throughout the keyboard entry process, the program must also refresh the dis-
plays if they are multiplexed and not controlled by shift registers or other hardware.
17-8 6809 Assembly Language Programming
c Start
J
Clear Display Array
Key Pointer = Start
of Display Array
Key Counter =
Key = Keyboard
Input Data
Figure 17-7 is the flowchart of a receive routine. We assume that the serial/
parallelconversion and error checking are done in hardware (e.g., by a UART). The
processor must:
If the message is meant for the terminal, turn off the Busy light and go to Dis-
play Answer routine.
In the event of any errors, request retransmission by going to the appropriate
RTRANS routine.
Program Design 17-9
c Start
D
Clear Display Array
Key Pointer = Start
of Display Array
Key Counter =
Key = Keyboard
Input Data
This routine involves a large number of decisions, and the flowchart is neither
simple nor obvious.
Clearly, we have come a long way from the simple flowchart (Figure 17-2) of
the first example. A complete set of flowcharts for the transaction terminal would be
a major task. It would consist of several interrelated charts with complex logic, and
would require a large amount of effort. Such an effort would be just as difficult as writing
a preliminary program, and not as useful, since you could not check the flowcharts on
the computer.
17-10 6809 Assembly Language Programming
MODULAR PROGRAMMING
Once programs become large and complex, flowcharting is no longer a satisfactory
design tool. However, the problem definition and the flowchart can help you divide the
program into reasonable sub-tasks. The division of the entire program into sub-tasks
or modules is called "modular programming." Clearly, most of the programs we pre-
sented in earlier chapters would typically be modules in a large program. The problems
that the designer faces in modular programming are how to divide the program into
modules and how to put the modules together.
1. A single module is easier to write, debug, and test than an entire program.
2. A module is likely to be useful in many places and in other programs, particu-
larly if it is reasonably general and performs a common task. You can build a
library of standard modules.
3. Modular programming allows the programmer to divide tasks and use pre-
viously written programs.
4. Changes can be incorporated into one module rather than into the entire
system.
5. Errors can often be isolated and then attributed to a single module.
6. Modular programming helps with project management, since it results in
obvious goals and milestones.
PRINCIPLES OF MODULARIZATION
An obvious problem is that there are no proven, systematic methods for
modularizing programs. We should mention the following principles: 2
1 Modules that reference common data should be parts of the same overall
module.
2. Two modules in which the first uses or depends on the second, but not the
reverse, should be separate.
3. A module that isused by more than one other module should be part of a
different overall module than the others.
4. Two modules in which the first is used by many other modules and the second
is used by only a few other modules should be separate.
5. Two modules whose frequencies of usage are significantly different should be
part of different modules.
program is difficult to modularize, you may need to redefine the tasks that
If a
are involved. Too many special cases or too many variables that require special han-
dling are typical signs of inadequate problem definition.
EXAMPLES
Modularizing the Switch and Light System
This simple program can be divided into two modules:
Module 1 waits for the switch to be turned on and turns the light on in
response.
Module 2 provides the one-second delay.
Module 1 is likely to be specific to the system, since it will depend on how the
switch and light are attached. Module 2 will be generally useful, since many tasks
require delays. Clearly, it would be advantageous to have a standard delay module that
could provide delays of varying lengths. The module will require careful documentation
so that you will know how to specify the length of the delay, how to call the module, and
what registers and memory locations the module affects.
A general version of Module 1 would be far less useful, since it would have to deal
with different types and connections of switches and lights.
You would probably find it simpler to write a module for a particular configuration
of switches and lights rather than try to use a standard routine. Note the difference be-
tween this situation and Module 2.
. :
• A delay module that provides the delay required to debounce the switches
• A switch and display module that reads the data from the switches and sends it
to the displays
• A Lamp Test module
Highly system-dependent modules such as the last two are unlikely to be generally use-
ful. This example is not one in which modular programming offers great advantages.
A general keyboard and display module could handle many keyboard- and dis-
play-based systems. The sub-modules would perform such tasks as:
Although the key interpretations and the number of digits will vary, the basic
and data display processes will be the same for many programs. Such
entry, data storage,
function keys as Clear would also be standard. Clearly, the designer must consider
which modules will be useful in other applications, and pay careful attention to those
modules.
The data transmission module could also be divided into such sub-modules as:
single module.
Error handling is a typical situation in which information should be hidden.
When a module detects a lethal error, it should not try to recover; instead, it should
inform the calling module of the error status and allow that module to decide how to
proceed. The reason is that the lower level module often lacks sufficient information to
establish recovery procedures. For example, suppose that the lower level module is one
that accepts numeric input from a user. This module expects a string of numeric digits
terminated by a carriage return. Entry of a non-numeric character causes the module to
terminate abnormally. Since the module does not know the context (i.e. is the numeric
string an operand, a lone number, an I/O unit number, or the length of a file?), it can-
not decide how to handle an error. If the module always followed a single error recovery
procedure, it would lose its generality and only be usable in those situations where that
procedure was required.
STRUCTURED PROGRAMMING
How do you keep modules distinct and stop them from interacting? How do you
write a program that has a clear sequence of operations so that you can isolate and
correct errors? One answer is to use the methods known as "structured program-
ming," whereby each part of the program consists of elements from a limited set of
structures and each structure has a single entry and a single exit.
Figure 17-8 shows a flowchart of an unstructured program. If an error occurs in
Module B, we have five possible sources for that error. Not only must we check each
sequence, but we also have to make sure that corrections do not affect any sequences.
The usual result is that debugging becomes like wrestling an octopus. Every time you
think the situation is under control, there is another loose tentacle somewhere.
BASIC STRUCTURES
The solution is to establish a clear sequence of operations so that you can isolate
errors.Such a sequence uses single-entry, single-exit structures. A program consists
of a sequence of structures; it may be a single statement or it may consist of structures
that are nested within each other to any level of complexity. The required structures
are listed below.
17-16 6809 Assembly Language Programming
the computer executes PI first, P2 second, and P3 third. PI, P2, and P3 may
be single statements or complex programs.
2. A conditional structure in which the execution of a program depends on a
condition.
There are many possible conditional structures, but a common one is "if C
then PI else P2" where C is a condition and PI and P2 are programs. The
computer executes PI if C is true, and P2 if C is false. Figure 17-9 shows the
logic of this structure. Note that it has a single entry and a single exit; the
computer cannot enter or leave PI or P2 other than through the structure.
3. A loop structure in which a program is repeated until (or as long as) a con-
dition holds.
There are many possible loop structures. A common one (called a "do-
while" structure) is "while C do P," where C is a condition and P is a pro-
gram. The computer continually checks C and then executes P as long as C is
true.
An obvious alternative is "until C do P" in which the computer continually
checks C and then executes P as long as C is false. Figures 17-10 and 17-11
show the logic of these alternatives. Both have a single entry and a single exit.
The computer will not execute P at all if C is originally in the exit state; thus P
is not executed at least once automatically as it is in a FORTRAN DO loop.
Alternative structures like "do P while C" or "repeat P until C" produce the
FORTRAN implementation in which the computer checks the condition after
executing the program (remember Figures 5-1 and 5-2). This approach is
often more efficient, but we will use only the form in Figure 17-10 to simplify
c Start
No
C true ^>
• Yes 1 '
P1 P2
1
•1
End
( )
c Start
D
*^ls^sS^Yes
C false
,. ? y
• No ' '
c End
^ P
the discussion. Most high-level structured languages allow all four alterna-
tives to provide flexibility. In mostprogram P must eventually force
cases, the
C into the exit state; if it does not, the computer will execute P endlessly (the
so-called DO FOREVER structure) as it must if P is the overall control pro-
gram for an instrument, computer peripheral, test system, or electronic game.
A case structure. Although it is not a primitive structure like our first three,
the case structure is so common that it merits a special description. The case
structure is "case I of PO, PI, ... Pn," where I is an index and PO, PI, ... Pn
, ,
on; it executes only one of the n programs. If I is greater than n (the number
of programs in the case statement) or after execution of one of the programs,
17-18 6809 Assembly Language Programming
the computer then executes the next sequential statement as shown in Figure
17-12. Obviously, we could implement a case structure as a series of condi-
tional structures, much as we could implement a jump table as a series of con-
ditional branches. However, the alternative implementations are long, awk-
ward, and difficult to expand.
1. Only the three basic structures, and possibly a small number of auxiliary
structures, are permitted. Variations of the conditional and loop structures
may be allowed.
Program Design 17-19
2. Structures may be nested to any level of complexity since any structure can,
in turn, contain any of the structures.
3. Each structure has a single entry and a single exit.
1. P2 included:
if X > then NPOS = NPOS + 1
else NNEG = NNEG + 1
Here no action is taken if C (X =£ 0) is false. P2 and "else" can be omitted in this case.
Some examples of the loop structure illustrated in Figure 17-10 are:
1. Form the sum of integers from 1 to N.
1 =
SUM =
do while I < N
1 = 1 + 1
SUM = SUM + I
end
The computer executes the loop as long as I < N. If N = 0, the program within the "do-
while" is not executed at all.
The computer executes the loop as long as the character in SENTENCE is not an ASCII
period. The count is zero if the first character is a period.
1. The sequence of operations is simple to trace. This allows you to test and
debug programs easily.
4. Theoreticians have proved that the given set of structures is complete; that is,
1. Only a few high-level languages (e.g., PL/M, PASCAL) will directly accept the
structures. The programmer therefore has to go through an extra translation
stage to convert the structures to assembly language code. The structured ver-
sion of the program, however, is often useful as documentation.
2. Structured programs often execute more slowly and use more memory than
unstructured programs.
3. Limiting the structures to the three basic forms makes some tasks very awk-
ward to perform. The completeness of the structures only means that all pro-
grams can be implemented with them; it does not mean that a given program
can be implemented efficiently or conveniently.
4. The standard structures are often quite confusing; e.g., nested "if-then-else"
structures may be very difficult to read, since there may be no clear indication
of where the inner structures end. A series of nested "do- while" loops can
also be difficult to read.
In the future, we expect the cost of memory to decrease, the average size of
microprocessor programs to increase, and the cost of software development to
increase. Therefore, methods like structured programming, which decrease software
development costs for larger programs but use more memory, will become more
valuable.
programming concepts are usually expressed in high-level
Just because structured
languages does not mean programming is not applicable to assembly
that structured
language programming. On the contrary, the assembly language programmer, with the
total freedom of expression that assembly level programming allows, needs the struc-
turing concept provided by structured programming. Creating modules with single
entry and exit points, using simple control structures and keeping the complexity of
each module minimal increases the productivity of the assembly language pro-
grammer.
Program Design 17-21
EXAMPLES
Structured Program for the Switch and Light System
The structured version of this example is:
SWITCH = OFF
do while SWITCH = OFF
READ SWITCH
end
LIGHT = ON
DELAY 1
LIGHT = OFF
ON and OFF must have the proper definitions for the switch and light. We assume
that DELAY is a module that provides a delay given by its parameter in seconds.
A statement in a structured program may actually be a subroutine. However, in
order to conform to the rules of structured programming, the subroutine cannot have
any exits other than the one that returns control to the main program.
Since "do-while" checks the condition before executing the loop, we set the
variable SWITCH OFF
before starting. The structured program is straightforward,
to
readable, check by hand. However, it would probably require somewhat
and easy to
more memory than an unstructured program, which would not have to initialize
SWITCH and could combine the reading and checking procedures.
Structured programs are not easy to write, but they can give a great deal of insight
into the overallprogram logic. You can check the logic of the structured program by
hand before writing any actual code.
Let us look at the keyboard entry for the transaction terminal. We will assume
that the display array is ENTRY, the keyboard strobe is KEYSTROBE, and the
keyboard data is KEYIN. The structured program without the function keys is:
NKEYS = 10
*
*CLEAR ENTRY TO START
*
do while NKEYS >
NKEYS = NKEYS - 1
ENTRY(NKEYS) =
end
*
FETCH A COMPLETE ENTRY FROM KEYBOARD
*
do while NKEYS < 10
if KEYSTROBE = ACTIVE then
begin
KEYSTROBE = INACTIVE
ENTRY (NKEYS) = KEYIN
NKEYS = NKEYS + 1
end
end
Adding the SEND key means that the program must ignore extra digits after it
has a complete entry, and must ignore the SEND key until it has a complete entry.
The structured program is:
NKEYS = 10
ENTRY (NKEYS) =
end
*
WAIT FOR COMPLETE ENTRY FOLLOWED BY SEND KEY
*
do while KEY t SEND or NKEYS / 10
if KEYSTROBE = ACTIVE then
begin
KEYSTROBE = INACTIVE
KEY = KEYIN
if NKEYS ? 10 and KEY ? SEND then
begin
ENTRY (NKEYS) = KEY
NKEYS = NKEYS + 1
end
end
end
1. The second if-then is nested within the first one, since the keys are only
entered after a strobe is recognized. If the second if-then were on the same
key could fill the entry, since its value would be
level as the first, a single
entered into the array during each iteration of the do-while loop.
2. KEY need not be defined initially, since NKEYS is set to zero as part of the
clearing of the entry.
Adding the CLEAR key allows the program to clear the entry originally by
simulating the pressing of CLEAR; i.e., by setting NKEYS to 10 and KEY to CLEAR
before starting. The structured program must also only clear digits that have previously
been filled. The new structured program is:
Note that the program resets KEY to zero after clearing the array, so that the operation
is not repeated.
:
We can similarly build a structured program for the receive routine. An initial
program could just look for the header and trailer characters. We will assume that RSTB
is the indicator that a character is ready. The structured program is
*
*CLEAR HEADER FLAG TO START
*
HFLAG =
*
*WAIT FOR HEADER AND TRAILER
do while HFLAG = or CHAR t TRAILER
*
*GET CHARACTER IF READY. LOOK FOR HEADER
*
if RSTB = ACTIVE then
begin
RSTB = INACTIVE
CHAR = INPUT
if CHAR = HEADER then HFLAG = 1
end
end
Now we can add the section that checks the message address against the three
digits in TERMINAL ADDRESS (TERMADDR). If any of the corresponding digits
are not equal, the ADDRESS MATCH flag (ADDRMATCH) is set to 1.
*
The program must now wait for a header, a three-digit identification code, and a
trailer. You must be careful of what happens during the iteration when the program
finds the header, and of what happens if an erroneous identification code character is the
same as the trailer.
A further addition can store the message in MESSG. NMESS is the number of
characters in the message; if it is not zero at the end, the program knows that the ter-
minal has received a valid message. We have not tried to minimize the logic expres-
sions in this program.
*
CLEAR FLAGS, COUNTERS TO START
*
HFLAG =
ADDRMATCH =
Program Design 17-25
ADDRCTR =
NMESS =
*
*WAIT FOR HEADER, DESTINATION ADDRESS, AND TRAILER
*
do while HFLAG = or CHAR t TRAILER or ADDRCTR / 3
*
*GET CHARACTER IF READY
*
if RSTB = ACTIVE then
begin
RSTB = INACTIVE
CHAR = INPUT
end
*
*READ MESSAGE IF DESTINATION ADDRESS = TERMINAL ADDRESS
*
complete, matching destination address. The program must work properly during the
iterations when it and the last digit of the destination
finds the header, the trailer
address. It must not trymatch the header with the terminal address or place the trailer
to
or the final digit of the destination address in the message. You might try adding the
rest of the logic from the flowchart (Figure 17-7) to the structured program. Note that
the order of operations is often critical. You must be sure that the program does not
complete one phase and start the next one during the same iteration.
Terminators
The particular structures we have presented are not ideal and are often awk-
ward. In addition, it can be difficult to determine where one structure ends and
another begins, particularly if they are nested. Theorists may provide better struc-
tures in the future, or designers may wish to add some of their own. A terminator for
each structure seems necessary, since indenting does not always clarify the situation.
"End" is a logical terminator for the "do-while" loop. There is no obvious terminator,
however,- for the "if-then-else" statement; some theorists have suggested "endif" or
"fi" ("if backwards), but these are both awkward and detract from the readability of
the program.
1. Begin by writing a basic flowchart to help define the logic of the program.
2. Start with the "sequential," "if-then-else," and "do-while" structures.
They are known to be a complete set, i.e., any program can be written in
terms of these structures.
3. Indent each level a few spaces from the previous level, so that you will know
which statements belong where.
4. Use terminators for each structure: e.g., "end" for the "do-while" and
"endif or "fi" for the "if-then-else." The terminators plus the indentation
should make the program reasonably clear.
5. Emphasize simplicity and readability. Leave lots of spaces, use meaningful
names, and make expressions as clear as possible. Do not try to minimize the
logic at the cost of clarity.
TOP-DOWN DESIGN
The remaining problem is how to check and integrate modules or structures.
Certainly we want to divide a large task into sub-tasks. But how do we check the sub-
tasks in isolation and put them together? The standard procedure, called "bottom-up
design," requires extra work in testing and debugging and leaves the entire integra-
tion task to the end. What we need is a method that allows testing and debugging in
the actual program environment and modularizes system integration.
This method is "top-down design." Here we by writing the overall super-
start
visor program. We replace the undefined sub-programs by program "stubs,"
tempor-
ary programs that may either record the entry, provide the answer to a selected test
problem, or do nothing. We then test the supervisor program to see that its logic is
correct.
Program Design 17-27
We proceed by expanding the stubs. Each stub will often contain sub-tasks,
which we will temporarily represent as stubs. This process of expansion, debugging,
and testing continues until all the stubs are replaced by working programs. Note that
testing and integration occur at each level, rather than all at the end. No special driver or
data generation programs are necessary. We get a clear idea of exactly where we are in
the design. Top-down design assumes modular programming, and is compatible with
structured programming as well.
1. The overall design may not mesh well with system hardware.
EXAMPLES
Top-Down Design of Switch and Light System
The first structured programming example actually demonstrates top-down
design as well. The program was:
SWITCH = OFF
do while SWITCH = OFF
READ SWITCH
end
LIGHT = ON
DELAY 1
LIGHT = OFF
These statements are really stubs, since none of them is fully defined. For example,
what does READ SWITCH mean? If the switch were one bit of input port SPORT, it
really means:
SWITCH = SPORT and SMASK
Similarly, DELAY 1 actually means (if the processor itself provides the delay)
REG = COUNT
do while REG t
REG = REG - 1
end
COUNT is the appropriate number to provide a one-second delay. The expanded ver-
sion of the program is:
SWITCH =
do while SWITCH =
SWITCH = SPORT and MASK
end
LIGHT = ON
REF = COUNT
do while REG ?
REG = REG - 1
end
LIGHT = not (LIGHT)
Certainly this program is more explicit, and could more easily be translated into
actual instructions or statements.
The program should wait for the HIGH ADDRESS button to be released. The
program should then display the values of the switches on the lights. This run checks for
the proper response to the HIGH ADDRESS button.
Program Design 17-29
Start
c )
Keyboard
ACK =
<T l!
No
V Yes w
Transmit
Display
Receive
End
( )
READ CPORT
LOADDRBUTTON = (CPORT) and LAMASK
When the LOW ADDRESS button is released, the program should display the
values of the switches on the lights. This run checks for the proper response to the LOW
ADDRESS button.
Similarly, we can expand the DATA button module and check for the proper
response to that button. The entire program will then have been tested.
When all the stubs have been expanded, the coding, debugging, and testing
stages will all be complete. Of course, we must know exactly what results each stub
should produce. However, many logical errors will become obvious at each level with-
out any further expansion.
This example, of course, will have more levels of detail. We could start with the
following program (see Figure 17-13 for a flowchart):
KEYBOARD
ACK =
do while ACK =
TRANSMIT
RECEIVE
end
DISPLAY
17-30 6809 Assembly Language Programming
HereVER=0 means that an entry has not been verified; COMPLETE =0 means
that the entry is incomplete. KEYIN and KEYDS are the keyboard input and display
routines respectively. VERIFY checks the entry. A stub for KEYIN would simply place
a random entry (from a random number table or generator) into the buffer and set
COMPLETE to 1.
C~ Start
J
T
VER =
Complete =
End
3
Is
Complete =
?
x Yes
KEYIN
Verify
KEYDS
9. Be aware of what the hardware can do. Do not hesitate to stop and do a little
the following tasks would be to implement if the data is simply scattered through
memory or organized in a long, linear array:
1 The operator of a machine tool wants to insert two extra cutting steps between
steps 14 and 15 of a 40-step pattern.
2. The operator of a chemical processing plant wants to see the last ten values of
the temperature at the inlet to tank #5.
3. An accounting clerk wants to enter a new account into an alphabetical list.
The processor may spend most of its time finding the data, moving from one
data item to the next, and organizing the data.
1. How are the data items related? Closely related items should be accessible
from each other, since such accesses will be frequent.
2. What kind of operations will be performed on the data? Simple linear struc-
tures are adequate if the data isalways handled in a single, fixed order.
However, more complex structures are essential if the tasks involve opera-
tions such as searching, editing, or sorting.
3. Can standard structures be used? Methods are readily available for handling
structures such as queues, stacks, and linked lists. Other arrangements will
will then find that many of the other stages of software development remain difficult
REFERENCES
1. D. L. Parnas (see the references below) has been a leader in the area of modular
programming.
2. Collected by B. W. Unger (see reference below).
3. Formulated by D. L. Parnas.
4. K. J. Thurber. and P. C. Patton. Data Structures and Computer Architecture, Lex-
ington Books, Lexington, Mass., 1977.
5. K. S. Shankar. "Data Structures, Types, and Abstractions," Computer, April 1980,
pp. 67-77.
The following references provide additional information on problem definition and pro-
gram design:
Chapin, N. Flowcharts, Auerbach, Princeton, N. J., 1971.
1976.
Halstead, M. H. Elements of Software Science, American Elsevier, New York, 1977.
Morgan, D. E. and D. J. Taylor. "A Survey of Methods for Achieving Reliable Soft-
ware," Computer, February 1977, pp. 44-52.
Myers, W. "The Need for Software Engineering," Computer, February 1978, pp.
12-25.
Parnas, D. L. "A Technique for the Specification of Software Modules with Exam-
ples," Communications of the ACM, May 1973, pp. 330-336.
Phister, M. Jr. Data Processing Technology and Economics, Santa Monica Publishing
Co., Santa Monica, Ca., 1976.
Schneider, V. "Prediction of Software Effort and Project Duration — Four New
Formulas," SIGPLAN Notices, June 1978, pp. 49-59.
Schneiderman, B. et al. "Experimental Investigations of the Utility of Detailed
Flowcharts in Programming," Communications of the ACM, June 1977, pp. 373-
381.
Software development must yield more than just a working program. A soft-
ware product must also include the documentation that allows it to be used, main-
tained, and extended. Adequate documentation is helpful during program debugging
and testing, and essential in the later stages of the program's life cycle.
SELF-DOCUMENTING PROGRAMS
Although no program is ever completely self-documenting, some of the rules
that we mentionedearlier can help. These include:
This program is undoubtedly easier to understand than the earlier version. Even
without further documentation, you could probably guess at the function of the pro-
gram and the meanings of most of the variables. Other documentation techniques can-
not substitute for self-documentation.
Some further notes on choosing names:
1. Use the obvious name when it is available, like TTY or CRT for output
devices, START or RESET for addresses, DELAY or SORT for subroutines,
COUNT or LENGTH for data.
2. Avoid acronyms like S16BA for SORT 16-BIT ARRAY. These seldom
mean anything to anybody.
3. Use full words or close to full words when possible, like DONE, PRINT,
SEND, etc.
4. Keep the names as distinct as possible. Avoid names that look alike, such as
TEMPI and TEMPI, or resemble operation codes or other built-in names.
COMMENTS
Comments are a simple form in which to provide additional documentation.
However, few programs (even those used as examples in books) have effective com-
ments. You should consider the following guidelines for good comments:
1. Don't explain the internal effects of the instruction. Instead, explain the
purpose of the instruction in the program. Comments like
DECB B = B - 1
do not help the reader understand the program. A more useful comment is
Remember that the standard manuals contain descriptions of how the pro-
cessor executes its The comments should explain what tasks
instructions.
the program is performing and what methods it is using.
2. Make the comments as clear as possible. Do not use abbreviations or
acronyms unless they are well-known (like ASCII, PIA, or UART) or stan-
dard (like no for number, ms for millisecond, etc.) Avoid comments like
DECB LN = LN - 1
or
DECB DEC. LN BY 1
understand, take the time to change it. If you find that the listing is getting
crowded, add some blank lines. The comments won't improve themselves;
in fact, they will just become worse as you leave the task behind and forget
exactly what you did.
10. Use comments heading in front of every major section, subsec-
to place a
tion, or subroutine. The heading shoulddescribe the functions of the code
that follows it; it should include information about the algorithm employed,
the inputs and outputs, and any incidental effects that may be produced.
11. If you modify a working program, use comments to describe the modifica-
tions that you made and identify the date and author of the revision. This
18-4 6809 Assembly Language Programming
information should go both at the front of the program (so a user can easily
one version from another) and
tell at the points where changes were actually
made.
Remember, comments are important. Good ones will save you time and effort.
Put some work into comments and try to make them effective.
EXAMPLES
1tM. COMMENTING A MULTIPLE-PR
ROUTINE
The basic program is:
LDB $40
LDX #$41
LDY #$51
ANDCC #%11111110
ADBYTE LDA ,X
ADC A ,Y+
STA ,X+
DECB
BNE ADBYTE
SWI
Important Points
First,comment the important points. These are typically intializations, data
fetches, and processing operations. Don't bother with standard sequences like updat-
ing pointers and counters. Remember that names are clearer than numbers, so use
them freely.
The new version of the program is:
Obscure Functions
Second, look for instructions that may not have obvious functions and explain
their purposes with comments. Here, the purpose of ANDCC#%11111110 (the 6800
operation code CLC is surely easier to understand) is to clear the Carry flag before
adding the least significant bytes.
Documentation 18-5
Some questions may be irrelevant and some answers may be obvious. Make sure,
however, that you wouldn't have to dissect the program to answer the important
questions. Remember also that too much explanation may be an obstacle to using the
program. Are there any changes you would like to see in the listing? If so, make
them — you are the one who has to decide if the commenting is adequate and reasona-
ble.
*
*THE FOLLOWING PROGRAM PERFORMS MULTI-BYTE BINARY ADDITION
*
* INPUTS: LOCATION 0040 CONTAINS LENGTH OF NUMBERS IN BYTES
* LOCATIONS 0041 ON CONTAIN ONE OPERAND STARTING WITH LSB'S
* LOCATIONS 0051 ON CONTAIN ONE OPERAND STARTING WITH LSB'S
* OUTPUTS: LOCATIONS 0041 ON CONTAIN SUM STARTING WITH LSB'S
*
LENGTH EQU $40 LENGTH OF NUMBERS IN BYTES
OPER1 EQU $41 LSB'S OF ONE OPERAND AND SUM
OPER2 EQU $51 LSB'S OF OTHER OPERAND
LDB LENGTH COUNT = LENGTH OF NUMBERS IN BYTES
LDX #0PER1 POINT TO LSB'S OF FIRST OPERAND, SUM
LDY #OPER2 POINT TO LSB'S OF SECOND OPERAND
ANDCC #%11111110 CLEAR CARRY FOR ADDITION OF LSB'S
ADBYTE LDA -X GET A BYTE FROM FIRST OPERAND
ADC A ,Y+ ADD A BYTE FROM SECOND OPERAND
STA ,x+ STORE SUM OVER FIRST OPERAND
DECB
BNE ADBYTE CONTINUE UNTIL ALL BYTES ADDED
SWI
LDA $60
AS LA
LDB #11
TBIT STA $8008
JSR BITDLY
RORA
ORCC #%00000001
DECB
BNE TBIT
SWI
18-6 6809 Assembly Language Programming
string of data, starting at the address in locations BUFPTR and BUFPTR + 1 and ending
with an "03" character (ASCII ETX). Furthermore, let us make the terminal a 30
character per second device with one stop bit (we will have to change subroutine
BITDLY). Try making the changes before looking at the listing.
Good comments will help you change a program to meet new requirements. For
example, try changing the last program so that it:
• Starts each message with ASCII STX (02) followed by a three-digit identifica-
tion code stored in memory locations IDCODE through IDCODE + 2.
Documentation 18-7
Transmits 40 characters, starting with the one located at the address in DPTR
and DPTR 4- 1.
FLOWCHARTS AS DOCUMENTATION
We have already described the use of flowcharts as a design tool in Chapter 17.
Flowcharts are also useful in documentation, particularly if:
Flowcharts are helpful if they give you an overall picture of the program. They are not
helpfulif they are just as difficult to read as the program listing.
The structured program can help you check the logic or improve it. Further-
more, since the structured program is machine-independent, it can also help you
implement the same task on another computer.
MEMORY MAPS
A memory map is simply a list of all the memory assignments in a program.
The map allows you to determine the amount of memory needed, the locations of data
or subroutines, and the parts of memory not allocated. The map is a handy reference for
finding storage locations and entry points and for dividing memory between different
routines or programmers. The map will also give you easy access to data and subroutines
ifyou need them in later extensions or in maintenance. Sometimes a graphical map is
more helpful than a listing.
:
A typical map is
Program Memory
Data Memory
Address Name Purpose
The map may also list additional entry points and include a specific description
of the unused parts of memory.
Parameter and definition lists at the start of the main program and each
subroutine make understanding and changing the program far simpler. The following
rules can help.
PARAMETERS
*
BOUNCE EQU 2 DEBOUNCING TIME IN MS
GOKEY EQU 10 IDENTIFICATION NUMBER FOR 'GO' KEY
MSCNT EQU $7A COUNT FOR 1 MS DELAY
OPEN EQU $0F INPUT PATTERN WHEN NO KEYS ARE PRESSED
TPULS EQU 1 PULSE LENGTH FOR DISPLAYS IN MS
*
DEFINITIONS
*
ALLHI EQU $FF ALL ONES INPUT
STCON EQU $80 OUTPUT FOR START OF CONVERSION PULSE
Of course, the RAM entries will usually not be in alphabetical order, since the
designer must order these to minimize the number of address changes required in the
program.
LIBRARY ROUTINES
Standard documentation of subroutines helps you build a library of programs
that are easy to use. If you describe each subroutine with a standard form, anyone can
see at a glance what the routines do and how to use them. You should organize the
forms carefully, dividing them, for example, by processor, language, and type of pro-
gram. Remember, without proper documentation and organization, using the library
may be more difficult than writing programs from scratch. If you are going to use
subroutines from a library or other outside source, you must know all their effects in
order to debug your overall program.
• Processor used
• Language used
• Parameters required and how they are passed to the subroutine
• Results produced and how they are passed to the main program
• Number of bytes of memory used
• Number of clock cycles required. This number may be an average or a typical
figure, or it may vary widely. Actual execution time will, of course, depend on
the processor clock rate and the memory cycle time.
Registers affected
Flags affected
A typical example
Error handling
Special cases
Requirements:
Memory — 7 bytes
Error Handling: Program ignores all carries. Carry flag reflects only the result of the last
Listing:
*
*SUM OF A SET OF 8-BIT DATA TTEMS
*
SUM8 CLRA CLEAR SUM TO START
ADBYTE ADDA ,X+ ADD AN ELEMENT TO THE SUM
DECB
BNE ADBYTE
RTS
Requirements:
Memory — 21 bytes, including the seven -segment code table (10 entries).
Time — 20 clock cycles if the data is valid, 12 if it is not.
Registers — A,B,X
All flags affected
Start:
End:
(B) = 6D Seven-segment representation of input data
Error Handling: Program returns zero in Accumulator B if the data is not a decimal digit.
Listing:
*
DECIMAL TO SEVEN-SEGMENT CODE CONVERSION
*
SEVEN CLRB GET ERROR CODE
CMPA #9 IS DATA A DECIMAL DIGIT?
BHI DONE NO, KEEP ERROR CODE AS RESULT
LDX #SSEG YES, GET SEVEN-SEGMENT CODE FROM TABLE
LDB A,X
DONE RTS
SSEG FCB $3F,$06,$5B,$4F,$66
FCB $6D,$7D,$07,$7F,$6F
Purpose: The program DECSUM adds two multi-digit decimal (BCD) numbers with
digits packed two to a byte.
Initial Conditions: Address of LSD's of one operand (and sum) in Index Register X,
address of LSD's of other operand in Index Register Y. Length of
numbers (in bytes) in Accumulator B. Numbers arranged starting
with LSD's at lowest address.
Final Conditions: Sum replaces number with starting address in Index Register X.
Requirements:
Memory — 13 bytes
Time — 8 + 23N clock cycles, where N is the number of bytes.
Registers - A,B,X,Y
All flags affected — Carry shows if sum produced a carry.
Start:
(0060) = 34
= 5534 is first operand
(0061) 55 f
I
(0050) "
, c f 1 588 is second operand
(0051)
End:
(0060) =22)
(0061) = 71 >7 122 is decimal sum
Carry = /
Error Handling: Program does not check the validity of decimal inputs. The contents
of Accumulator B must be 1 or more.
Listing:
TOTAL DOCUMENTATION
Complete documentation of microprocessor software will include all or most of
the elements that we have mentioned.
DOCUMENTATION PACKAGE
The total documentation package may involve:
• General flowcharts
Documentation 18-13
• Programmer's flowcharts
• Data flowcharts
• Structured programs
Even this package is sufficient only for non-production software. Production soft-
ware also requires the following documents:
• Program Logic Manual
• User's Guide
• Maintenance Manual
User's Guide
The User's Guide is the most important single piece of documentation. No mat-
ter how well-designed the system may be, it no one can understand
will not be useful if
its operations or take advantage of its features. The User's Guide should explain
system features and their use, provide frequent examples that clarify the text, and
give tested step-by-step directions. The writing of User's Guides requires care and
objectivity, since the writer must be able to take an outsider's point of view.
One problem in writing User's Guides is the need to avoid overwhelming the
beginner or taxing the patience of the experienced user. Two separate versions can help
overcome this problem. A guide for the beginner can explain the most common
features of the program with the aid of simple examples and detailed discussions. A
guide for the experienced user can provide more extensive descriptions of features
and fewer details. Remember that the beginner needs help getting started, whereas the
experienced user wants organized reference material.
Maintenance Manual
The maintenance manual is designed for the programmer who has to modify the
system. should explain the procedures for any changes or expansion that have been
It
IMPORTANCE OF DOCUMENTATION
Documentation should not be taken lightly or left to the last minute. Good docu-
mentation, combined with proper programming practices, is not only an important part
of the final product but can also make development simpler, faster, and more produc-
tive. The designer should make consistent and thorough documentation part of every
stage of software development.
19
Debugging
As we noted at the beginning of this section, debugging and testing are among the
most time-consuming stages of software development. Even though such methods as
modular programming, structured programming, and top-down design can simplify
programs and reduce the frequency of errors, debugging and testing are still difficult
because they are so poorly defined. The selection of an adequate set of test data is
seldom a clear or scientific process. Finding errors sometimes seems like a game of "pin
the tail on the donkey," except that the donkey is moving and the programmer must
position the tail by remote control. Surely, few tasks are as frustrating as debugging pro-
grams.
This chapter will first describe the tools available to aid in debugging. It will
then discuss basic debugging procedures, describe the common types of errors, and
present some examples of program debugging. The next chapter will describe how to
select test data and test programs.
We will describe only the purposes of most debugging tools. There is little stan-
dardization in this area and we cannot discuss all the available products. The examples
show the uses, advantages, and limitations of some common tools.
Debugging tools have two major functions. One is to pin the error down to a short
section of the program; the other is to provide more detailed information about what the
computer is doing than is provided by normal runs and so make the source of the error
obvious. Current debugging tools do not find and correct errors by themselves; you
must know enough about what is happening to recognize and correct the error when the
debugging tools zero in on it and show its effects in detail.
19-2 6809 Assembly Language Programming
A single-step facility
A breakpoint facility
A trace facility
A Register Dump Program (or utility)
SINGLE STEP
The single-step facility allows you to execute the program one instruction or
one memory cycle at a time. Only some 6809-based microcomputers have this
facility, since the circuitry is fairly complex. Of course, all that you can see when the
computer executes a single-step are the states of the output lines that you are
monitoring. The most important lines are:
• Data Bus
• Address Bus
• Control Lines
• BUSY and READ/WRITE
If you monitor these lines either in hardware or in software, you can see the
progression of addresses, instructions, and data as the program You can
is executed.
determine what kinds of operations the CPU is performing. This information will be
sufficient for you to identify such errors as Jump or Branch instructions with incorrect
conditions or destinations, omitted or incorrect addresses, incorrect operation codes,
and incorrect data values. However, you cannot see the contents of registers, flags, or
memory locations without some additional debugging tool.
Furthermore, a single-step mode obviously slows the processor way below its
normal speed. You cannot check delay loops or I/O operations in real time. Nor can a
single-step mode help you find timing errors or errors in the interrupt or DMA systems.
In fact, the single-step mode typically operates at less than one millionth of normal pro-
cessor speed. To single-step through one second of real processor time would require
more than ten days. The single-step mode, therefore, is useful only to check the logic
of a short sequence of instructions.
BREAKPOINT
A breakpoint is a place at which the program will automatically halt or wait so
that the user can examine the current status of the system. The program will not con-
tinue until the user orders its resumption. Breakpoints allow you to check or pass
through an entire section of a program. Thus, to see if an initialization routine is correct,
you can place a breakpoint at the end of it and run the program. You can then check
memory locations and registers to see if the entire section is correct. However, note that
if the section is not correct, you still must pinpoint the error, either with earlier break-
points or with a single-step mode.
Debugging 19-3
Breakpoints complement the single-step mode. You can use breakpoints either
through sections that you know are correct. You can
to localize the error or to pass
then do the detailed debugging in the single-step mode. In some cases, breakpoints do
not affect program timing. They can then be used to check input/output and interrupts.
Inserting Breakpoints
The simplest method for inserting breakpoints is to replace the first byte or
bytes of an instruction with a Software Interrupt instruction. Any Software Interrupt
instruction will automatically direct the processor to the breakpoint routine and save the
current values of all the registers (except the Hardware Stack Pointer) in the Hardware
Stack. Figure 15-2 shows the order in which the processor saves its registers. The break-
point routine can print all the register contents by starting at the address in the Hardware
Stack Pointer. The only problem is that the return program counter value will be the
address following the Software Interrupt. You may want to reduce that value by 1 or 2,
either to display the actual breakpoint address or to resume the program correctly after
restoring the original instruction. Typical programs to reduce the value are (using the
methods discussed in Chapter 15):
2. Decrement the return address by 2 (if you are using SWI2 or SWI3)
LDX $0A,S GET RETURN ADDRESS
LEAX -2,X MOVE IT BACK 2 (SWI2 AND SWI3 USE
TWO BYTES EACH)
STX $0A,S PUT ADJUSTED RETURN ADDRESS IN STACK
C Start
D
Store all registers
in Stack.
Count = Number
of bytes in
registers = 14
Data Pointer =
Stack Pointer
^
Print (Data Pointer)
as two hex digits
Data Pointer =
Data Pointer + 1
Count = Count - 1
c End
3
Figure 19-2. Flowchart of Register Dump Program
Many monitors have facilities for automatically inserting (setting) and remov-
ing (clearing) breakpoints based on one of the Software Interrupt instructions. Such
breakpoints do not affect the timing of the program until one of them is executed.
However, you obviously cannot replace instructions that are in ROM or PROM. Other
monitors implement breakpoints by actually checking the address lines or the Pro-
gram Counter in hardware or in software. This method allows the user to set break-
points on addresses in ROM or PROM, but it may affect system timing if the address
must be checked in software. A more powerful facility would allow the user to enter an
address to which the processor would transfer control. Another possibility would be a
return dependent on a switch as in the following example.
Debugging 19-5
Of course, other PI A data or control lines could also be used. Remember that RTI
reenables the interrupts automatically. If a PIA interrupt is used, the service routine
must read the PIA data register to clear the interrupt status bit.
TRACE
The trace facility allows you to see intermediate results. A simple trace prints the
contents of all registers and other variables after each instruction is executed. This
obviously produces a large amount of information, most of which is irrelevant or repeti-
tive. Better trace facilities allow you to specify what you want traced and how often
you want the values printed. This results in less information, but means that you must
decide what you need before instituting the trace.
The following approach will help you use traces:
1. Decide what you need before executing the trace. Otherwise, you will not
know what to do with the results.
2. Start by tracing only one or two variables and printing the results infre-
quently. This will give you less information to analyze at one time.
3. Use breakpoints to limit the extent of the trace.
4. Use whatever facilities your computer has to mark the output Otherwise,
you end up with pages of unidentified numbers and you will spend most
will
of your time just figuring out what they are.
REGISTER DUMP
A Register Dump utility is a program that lists the contents of all the CPU
registers. This information is usually not directly obtainable. The following routine will
S ,
Value Register
AO SH
6B SL
DC CC
27 A
E5 B
01 DP
B6 XH
97 XL
BD YH
14 YL
05 UH
F3 UL
D7 PCH
3C PCL
print the contents of all the registers on the system printer, if we assume that
PRTHEX prints the contents of Accumulator A as two hexadecimal digits. Figure 19-
2 is a flowchart of the program and Figure 19-3 shows a typical result. We assume that
the routine is entered with a BSR or JSR instruction that stores the old Program Counter
at the top of the Hardware Stack. An interrupt or Software Interrupt instruction will
store all the registers (except the Hardware Stack Pointer) on the Hardware Stack.
MEMORY DUMP
A Memory Dump is a program that lists the contents of memory on an output
device (such as a printer). This is a much more efficient way to examine data arrays or
entire programs than just looking at single locations. However, large memory dumps are
not useful (except to supply scrap paper) because of the sheer mass of information that
.
Debugging 19-7
they produce. They may also take a long time to execute on a slow printer. Small dumps
may, however, provide the programmer with a reasonable amount of information that
can be examined as a unit. Relationships such as regular repetitions of data patterns
or offsets of entire arrays may become obvious.
A general dump can be difficult to write. The programmer should be careful of the
following situations:
1. The size of the memory area exceeds 256 bytes, so that an 8-bit counter will
not suffice.
2. The ending address is below the starting address. This can be treated as an
error, since the user would seldom want to print the contents of memory in an
unusual order.
Since the speed of the Memory Dump depends on the speed of the output device,
the efficiency of the routine seldom matters. The following program will ignore cases
where the ending address is below the starting address, and will handle areas of any
size. We assume that the starting address is in memory locations START and START +
1 and the ending address is in memory locations LAST and LAST + 1
*
*PRINT CONTENTS OF MEMORY LOCATIONS BETWEEN START AND LAST
*
DUMP LDX START GET STARTING ADDRESS
CHKEND CMPX LAST ARE WE BEYOND ENDING ADDRESS?
BHI DONE YES, DUMP COMPLETED
LDA ,x+ NO, GET CONTENTS OF NEXT LOCATION
JSR PRNT1 PRINT CONTENTS AS 2 HEX DIGITS
BRA CHKEND
DONE RTS
Figure 19-4 shows the output from a dump of memory locations 1000 through
101F.
This routine correctly handles the case in which the starting and ending addresses
are the same (try it!). You must interpret the results carefully if the dump area includes
dump subroutine
the stack, since the itself uses the stack. PRNT1 may also change
memory and stack locations.
A memory dump can display the data in many different formats. Common alter-
natives are ASCII characters or pairs of hexadecimal digits for 8-bit values and four hex-
adecimal digits for 16-bit values. You should select a format based on how you plan to
use the dump. If the area of memory contains object code, a hexadecimal format will be
best, since you can look up the meanings of the operation codes in Appendix D or on a
standard summary card. The following example shows a common format for displaying
the output of a dump; since this approach provides both the hexadecimal and the ASCII
forms, you can use it to examine areas containing either object code or ASCII text.
23 1F 60 54 37 28 3E 00
6E 42 38 17 59 44 98 37
47 36 23 81 E1 FF FF 5A
34 ED BC AF FE FF 27 02
Each line consists of three parts: a starting address (the address of the first byte
shown on the line), the contents of that address and the following seven or fifteen bytes
in hexadecimal form, and the ASCII representation of those contents. You might try
revising the memory dump program so it produces output in this format.
Many variations of both these tools exist; we shall discuss only the standard
features.
SOFTWARE SIMULATOR
The simulator is the computerized equivalent of the pencil-and-paper computer.
It is a computer program that goes through the operating cycle of another computer,
keeping track of the contents of all the registers, flags, and memory locations. We
could, of course, do this by hand, but it would require a large amount of effort and close
attention to the exact effects of each instruction. The simulator program never gets tired
or confused, forgets an instruction or register, or runs out of paper.
Most simulators are large FORTRAN programs. They can be purchased or used
on the time-sharing service. The 6809 simulator is available in several versions from
different sources.
Typical Features
3. A trace facility that will print the contents of particular registers or memory
locations whenever the program changes or uses them.
4. A load facility that allows you to set values initially or change them during
the simulation.
Some simulators can also simulate input/output, interrupts, and even DMA.
.
Debugging 19-9
Advantages
The simulator has many advantages:
1 Itcan provide a complete description of the status of the computer, since it is
not restricted by pin limitations or other characteristics of the underlying cir-
cuitry.
2. Itcan provide breakpoints, dumps, traces, and other facilities, without using
any of the processor's memory space or control system. These facilities will
therefore not interfere with the user program.
3. Programs, starting points, and other conditions are easy to change.
4. All the facilities of a large computer, including peripherals and software, are
available to the microprocessor designer.
Limitations
On the other hand, the simulator is limited by its software base and its separa-
tion from the real microcomputer. The major limitations are:
1. The simulator cannot help with timing problems, since it operates far more
slowly than real time and does not model actual hardware or interfaces.
2. The simulator cannot fully model the input/output section.
3. The simulator is usually quite slow. Reproducing one second of actual pro-
cessor time may require hours of computer time. Using the simulator can be
quite expensive.
The simulator represents the software side of debugging; it has the typical
advantages and limitations of a wholly software-based approach. The simulator can
provide insight into program logic and other software problems, but cannot help with
timing, I/O, and other hardware problems.
LOGIC ANALYZER
The logic or microprocessor analyzer is the hardware approach to debugging.
Basically, the analyzer is the parallel digital version of the standard oscilloscope. The
analyzer displays information in binary, hexadecimal, or mnemonic form on a CRT, and
has a variety of triggering events, thresholds, and inputs. Most analyzers also have a
memory so that they can display the past contents of the busses.
The standard procedure is to set a triggering event, such as the occurrence of a
particular address on the Address Bus or instruction on the Data Bus. For example, one
might trigger the analyzer if the microcomputer tries to store data in a particular area or
Important Features
Logic analyzers vary in many respects. Some of these are:
2. Amount of memory. Each previous state that is saved will occupy several
bytes.
All these factors are important in comparing different logic and microprocessor
analyzers, since these instruments are new and unstandardized. A tremendous variety
of products is already available and this variety will become even greater in the future. 1
Logic analyzers, of course, are necessary only for systems with complex timing.
Simple applications with low-speed peripherals have few hardware problems that a
designer cannot handle with a standard oscilloscope.
maximum benefit from debugging runs, since you will get rid of many simple errors
ahead of time.
A quick review of hand checking questions:
1. Isevery element of the program design in the program (and vice versa for
documentation purposes) ?
2. Are all registers and memory locations used inside loops initialized before the
grams often still don't work. with the problem of how to find the
The designer is left
mistakes. The hand checklist provides a starting place if you didn't use it earlier.
PROGRAMMER ERRORS
Here are some of the errors that you may not have eliminated using the
checklist:
2. Inverting the logic of a conditional jump, such as using Branch on Carry Set
when you should use Branch on Carry Clear. Remember the effects of com-
parison (CMP) and subtraction (SBC or SUB) instructions, since these are
the most common flag-setting operations. If A is the contents of Accumula-
tor A and M the contents of the effective address, CMPA (or SUBA) sets
the Carry and Zero flags as follows:
Zero flag = 1 if A = M
Zero flag = if A ^ M
Carry flag = 1 if A < M ) A
ASSUm,ng
..
UnS,gned 0perands
Carry flag = if A > M I
Note that the Carry flag is cleared in the equality case (A = M). So
Branch on Carry Set causes a branch if A < M
and Branch on Carry Clear
causes a branch if A > M. If you want to handle the equality case in the
opposite way, use Branch if Lower or Same (causes a branch if A < M) or
Branch if Higher (causes a branch if A > M). For example, if you want to
force a branch when A is greater than or equal to 10, use
CMPA #10
BCC ADDR
3. Updating counters, pointers, and indexes in the wrong place or not at all.
Be sure that there are no paths through a loop that either skip or repeat
the updating instructions. Note the difference between the 6809's autoincre-
menting and autodecrementing:
In autoincrementing, the processor increments the index register or
stack pointer after using its contents.
In autodecrementing, the processor decrements the index register or
stack pointer before using its contents.
Register X, not Index Register X itself. Note the difference between INC ,X
and INX (or LEAX 1,X); the former adds 1 to the contents of an 8-bit
memory location (addressed by Index Register X) while the latter adds 1 to
the contents of a 16-bit index register.
8. Confusing data and addresses.
Remember LDX #$1000 loads Index Register X with the number
that
1000 16 whereas
, LDX $1000 loads Index Register X with the contents of
memory locations 1000 and 1001 A similar distinction applies to LDA
I6 16
.
COUNT and LDA #COUNT. This problem becomes more serious if you
are using the indirect addressing modes. Now you must remember that LDA
,X+ loads Accumulator A from the address in Index Register X and then
adds 1 to Index Register X, whereas LDA [,X++] loads Accumulator A
from the address contained in the two memory bytes starting at the address
in Index Register X and then adds 2 to Index Register X. Mathematical
descriptions of what is happening are shorter and more meaningful than
word descriptions, but either may be difficult to understand.
9. Accidentally reinitializing a register or memory location.
Make sure that no branches transfer control back into the initialization
routine. Calculating a result and then writing over it is a common error that
is difficult to trace.
17. Forgetting that addresses or 16-bit data occupy two bytes of memory.
Extended or indirect addresses or 16-bit data occupy two memory loca-
tions. The occupy two memory locations when they are
16-bit registers also
stored in LDX $40 loads Index Register X from
memory. For example,
memory locations 0040 and 0041. Similarly, STU $50 stores the User Stack
Pointer in locations 0050 and 0051. Note that CMPX, CMPU, CMPY,
CMPS, LDX, LDU, LDY, LDS, etc. can all use 8-bit direct page addresses,
even though they are 16-bit operations.
18. Confusing the Stacks and their pointers.
Instructions like LD, TFR, LEA, and EXG affect the Stack Pointers,
not the contents of the Stacks. PSH and PUL transfer data to and from the
Stacks. Remember that JSR, BSR, RTI, RTS, and SWI all use the Hardware
Stack. Remember also that you must initialize the Hardware Stack Pointer
before calling any subroutines or allowing any interrupts.
19. Changing a register or memory location before using it.
Remember that LD, ST, and TFR change the contents of the
all
destination, but not the source. EXG, on the other hand, changes both of its
operands (assuming they are not the same)
20. Forgetting to transfer control past sections of the program that should not
be executed.
Remember that the computer will proceed sequentially through
memory unless specifically instructed to do otherwise. Thus you may need
some unconditional branches to avoid routines that should not be executed.
21. Changing registers that you are using for addressing.
Be particularly careful of instructions like LDA A,X which loads
Accumulator A using the index in Accumulator A. The index in Accumula-
tor A is destroyed, so you had better not need it again. Instructions that use a
register both for addressing and as a destination can be powerful, but may
also be confusing.
23. Ignoring the physical limitations of I/O devices and interface chips.
While we may address interface chips as if they were memory locations,
they may not behave like memories. Storing data in an input port seldom
makes sense, nor does loading data from an output port unless the port is
latched and buffered. In particular, be careful of instructions like shifts,
clear, complement, and test which both read and write a memory location.
They may have unpredictable effects on I/O ports and interface chips.
Debugging 19-15
tion had been removed. For example, JMP $A000 loads the address A000 16
into the Program Counter, whereas LDX $A000 loads the contents of
addresses A000 16 and A001 l6 into Index Register X. The equivalent JMP
instruction would be JMP [$A000]. A similar distinction applies to all the
indexed modes; JMP or JSR using an indirect mode has the same effect on
the Program Counter that LDX using the corresponding non-indirect mode
would have on Index Register X. This distinction makes instructions that
use indirect addressing even more confusing than they would normally be.
ASSEMBLER-RELATED ERRORS
The use of an assembler is the only practical way to convert source programs
into object code, but it does introduce a few annoying errors. In particular,
1. Be careful of what your assembler may use as defaults. For example, the
standard 6809 assembler assumes that unmarked numbers are decimal and
that instructions without designated addressing modes use direct addressing
(if on the direct page) or extended addressing (otherwise) You must specify.
INTERRUPT-DRIVEN PROGRAMS
register in order to clear the interrupt flag. The reading is necessary even if the
interrupt is from an output device or a real-time clock. Otherwise, the inter-
rupt will remain active and will be recognized again as soon as the processor
reenables it.
Debugging 19-17
condition code register, so that it exits with the interrupt system in its original
state.
Other Approaches
These lists are far from complete, but they should suggest some places where you
can look for errors. Unfortunately, debugging computer programs is not an exact
science; even the most systematic approach can leave you with baffling problems. 3
Sometimes, your best bet may be to let the problem sit overnight or have someone
with a fresh viewpoint look at it.
PROGRAM EXAMPLES
19-1. DEBUGGING A CODE CONVERSION PROGRAM
The program converts a decimal number in memory location 0040 to a seven-seg-
ment code in memory location 0041. It blanks the display if memory location 0040 does
not contain a decimal number.
1 We have omitted the section that clears Result if the data is not a decimal
digit.
For example, if the data is zero, CMPA #9 clears the Carry flag and causes a
branch. The correct version is
the mnemonics BLO and BHS after comparisons instead of BCS and BCC.
The 6809 has many conditional branches and you must be careful to choose the
right one.
19-18 6809 Assembly.Language Programming
c Start
}
Data = (0040)
Yes
(0041) = Result
c End
D
Figure 19-5. Flowchart of Decimal to Seven-Segment Conversion
Second Program:
CLRB GET BLANK CODE FOR DISPLAY
LDA $40 GET DATA
CMPA #9 IS DATA A DECIMAL DIGIT?
BHI DONE NO, KEEP ERROR CODE
LDX SSEG YES, GET BASE ADDRESS OF CODE TABLE
LDA ,X GET ELEMENT FROM TABLE
STA $41 SAVE SEVEN-SEGMENT CODE
SWI
FCB $3F,$06,$5B,$4F,$66
$3F,
FCB $6D,$7D,$07,$7D,$6F
$6D,
The hand check did not uncover any errors in this version.
Single Step
Since the program is simple, the next stage is to single-step through it with real
data. We chose the following data for the trials:
For the first trial, we placed zero in memory location 0040. The program pro-
ceeded with no apparent errors until it reached the LDA ,X instruction. At that point,
Index Register X contained 3F06, an address that did not even exist in our computer.
Clearly, something had gone wrong.
Hand Check
It was now time for more hand-checking. Since we knew that BHI DONE was cor-
rect, the error had to be further along in the program. The hand check showed that LDX
SSEG placed 3F06 in Index Register X, since it loaded the register with the contents of
the two bytes starting at address SSEG. What we want to place in Index Register X is the
address SSEG, not its contents; that is, we want immediate addressing, not direct
addressing. This change creates an awkward patching problem in the object code, since
LDX with immediate addressing occupies 3 bytes of memory, whereas LDX with direct
addressing occupies only 2 bytes.
Run Test
With this correction (LDX#SSEG LDX
SSEG), the program worked
instead of
correctly when the data was zero. However, when it produced the same
the data was 9,
result as for (3F 16 ). A hand check of the LDA ,X instruction showed that the program
was not performing any indexing; it was just loading Accumulator A from the address in
Index Register X. What we want is the accumulator indexed mode in which the pro-
cessor adds the index in Accumulator A to the base address in Index Register X. So we
replaced LDA ,X with LDA A,X.
Third Program:
Data Result
00 3F
09 6F
OA 0A
6B 6B
Exhaustive Test
Since the program was simple, we could easily test it on each decimal digit. The
results were:
Data Result
3F
1 06
2 5B
3 4F
4 66
5 6D
6 7D
7 07
8 7D
9 6F
Note that the result for 8 is wrong — it should be 7F, not 7D. Since the program
works for all other digits, the error is almost surely in the table. In fact, the eighth entry
in the table had been typed incorrectly.
Final Program:
*
DECIMAL TO SEVEN-SEGMENT CONVERSION
*
CLRB GET BLANK CODE FOR DISPLAY
LDA $40 GET DATA
CM PA #9 IS DATA A DECIMAL DIGIT?
BHI DONE NO, KEEP ERROR CODE
LDX #SSEG YES, GET BASE ADDRESS OF CODE TABLE
LDB A,X GET ELEMENT FROM TABLE
DONE STB $41 SAVE SEVEN-SEGMENT CODE
SWI
SSEG FCB $3F,$ 5B,$4F,$66
FCB $6D,$7D,$07,$7F,$6F
$6D,$
The errors that we found in this example are typical of the ones that 6809 as-
sembly language programmers should expect. They include:
Note that straightforward instructions (like AND, DEC, or INC) and simple
addressing modes seldom cause any problems.
)
Debugging 19-21
C Start
J
3
Interchange flag =
Count = Length
1
of Array
Pointer = Start
of Array
Interchange
(Pointer),
(Pointer + 1
Interchange flag
=
Pointer =
Pointer + 1
Count = Count - 1
The execution of CMPB 1,X causes the CPU to calculate 30 — 37. The Carry flag
is set since the subtraction requires a borrow. This an example should result in
interchange, but BLO COUNTbranches around the interchange instructions. BHS
COUNT produces the proper branch in this case. If the two numbers are equal, the com-
parison will clear the Carry flag so BHS COUNT is again correct.
How about BNE PASS at the end of the program? If there are any elements out of
order, the program will clear the interchange flag and the contents of memory location
0040 will be zero. So the branch is inverted; it should be BEQ PASS.
Now let us check the first iteration by hand. The initialization (the first four
instructions) produces the following values:
= COUNT
(A) Length of array
= 0042
(X) Starting address of array
(0040) = 1 Interchange flag
Clearly the logic is incorrect. If the first two numbers are out of order (as in our
example), the results after the first iteration should be:
instead of LDB ,X; CMPB ,X instead of CMPB ,X (the autoincrementing has increased
1
Index Register X by 1); and STB ,X instead of STB 1,X. We must be careful to incre-
ment X in an instruction that will be executed regardless of the outcome of BHS
COUNT. The interchange requires a bit more care and the use of both Accumulators
(remembering to save the count in the Hardware Stack and restore it at the end):
Second Program:
LDA #1 SET INTERCHANGE FLAG
STA $40
LDA $41 COUNT = LENGTH OF ARRAY
LDX #$42 POINT TO START OF ARRAY
PASS LDB ,X+ IS PAIR OF ELEMENTS IN ORDER?
CMPB ,X
BHS COUNT
PSHS A NO, INTERCHANGE ELEMENTS
LDA ,X
STB ,x
STA -1,X
PULS A
DECA IS PASS THROUGH ARRAY COMPLETE?
BEQ PASS NO, GO ON TO NEXT PAIR
TST $40 WERE ANY INTERCHANGES PERFORMED?
BNE PASS YES, MAKE ANOTHER PASS
SWI
How about the last iteration? Let us assume that the array contains three elements:
Each time through the loop, the program increments Index Register X by 1. So, at the
start of the third (last) iteration,
This is incorrect; the program is working on data beyond the end of the array. In
fact, the previous iteration should have been the last one, since the number of pairs is
one less than the number of elements. The last element in the array has no successor for
comparison. The correction is to reduce the number of iterations by 1: i.e., place DEC A
after LDA $41.
few bytes of memory to avoid problems that could be difficult to identify and correct.
Third Program:
Array to be sorted
!S2^!"2?[
(0043) 01 )
This set consists of two elements in the wrong order. The program should require
two passes. The first pass should exchange the elements, producing:
(0042) - 01
{ Reordered array
(0043) - 00
The second element should find the elements already in the proper (descending)
order and produce:
(0040) 01 Interchange flag
instead. Each breakpoint will halt the computer and print the contents of the key
registers. The breakpoints will come:
Register Contents
cc FO
B 00
A 01
X 0042
These are all correct, so the program is performing the initialization properly in
this case.
The results at the second breakpoint are:
gister Contents
CC F9
B 00
A 01
X 0043
Register Contents
CC F1
B 00
A 01
X 0043
Examining memory shows:
(0042) = 01
(0043) = 00
CC FO
B 00
A 00
X 0043
Examining memory shows:
(0040) = 01
The Zero flag (bit 2 of the Condition Code Register) is incorrect, since an
interchange occurred and the program should branch and go back through the array
again. Memory location 0040 (the interchange flag) should contain 0, rather than 1.
Examining the program shows that it never clears the interchange flag; the correction is
to insert the instruction CLR $40 after BHS COUNT. The program now clears the
interchange flag as soon as it determines that an interchange is necessary.
19-26 6809 Assembly Language Programming
We can continue by clearing memory location 0040 and setting the Zero flag (CC
= F4 16 instead of F0 16 ). The results at the second iteration of the second breakpoint are:
Register Contents
CC F9
B 00
A 01
X 0044
The program has not reinitialized the registers (particularly Index Register X).
The condition branch that sends the program through the entire array again should
transfer control to the initialization routine; note that we do not need to check the length
of the array a second time to eliminate the trivial cases.
Final Program:
(0042) = 00 )
Array to be sorted
(0043) = 00 J
(0042) = 01
Array to be sorted
(0043) = 00
Debugging 19-27
REFERENCES
1. For more information about logic analyzers, see:
J. McLeod. "Special Report: Logic Analyzers," Electronic Design, March 29, 1980.
pp. 48-56.
C. A. Ogdin. "Setting up a Microcomputer Design Laboratory," Mini-Micro Systems,
May 1979, pp. 87-94.
I. H. Spector and R. Muething. "Logic Analyzer Deploys Its Full Strength,"
Electronic Design, March 29, 1980, pp. 177-214.
A = A© B
B = A$ B
A = A© B
You can verify this sequence if you are handy at Boolean algebra and the use of
DeMorgan's theorem.
20
Testing
Program testing 1 is closely related to program debugging. We must test the pro-
gram on the data that we used to debug it; for example,
• Trivial cases such as no data or a single statement
• Special cases that the program singles out for some reason
• Simple cases that exercise particular parts of the program
The program does not distinguish any other cases. Here debugging and testing
are virtually the same.
In the sorting program, the problem is more difficult. The number of elements
could range from to 255, and each of the elements could lie anywhere in that range.
The number of possible cases is therefore enormous. Furthermore, the program is
moderately complex. How do we select test data that will give us a degree of confidence
in that program? Here testing requires some design decisions. The testing problem is
particularly difficult if the program depends on sequences of real-time data. How do we
select the data, generate it, and present it to the microcomputer in a realistic manner?
20-2 6809 Assembly Language Programming
TESTING AIDS
Most of the tools mentioned earlier for debugging are helpful in testing also.
Logic or microprocessor analyzers can help check the hardware; simulators 2 can help
check the software. Other tools can also be of assistance:
1. I/O simulations that can simulate many devices from a single input and a
single output device.
8. Test generation programs that can generate random data or other distribu-
tions.
Formal testing theorems exist, but are only practical for verifying short pro-
grams. You must be careful that the test equipment does not invalidate the test by
modifying the environment. Often test equipment may buffer, latch, or condition
input and output signals. The actual system may not do this and may therefore
behave differently.
Furthermore, extra software in the test environment may use some of the
memory space or part of the interrupt system. It may also provide error recovery and
other features that will not exist in the final system. A software test bed must be just
as realistic as a hardware test bed since software failure can be just as critical as hardware
failure.
Emulations and simulations are, of course, never precise. They are usually
adequate for checking logic, but can seldom help test interfaces or timing. On the
other hand, real-time test equipment does not provide much of an overview of the pro-
gram logic and may affect the interfacing and timing.
Structured Testing
Testing should, of course, be part of the total development procedure. Top-down
design and structured programming provide for testing as part of the design. This is
called structured testing. Each module within a structured program should be checked
separately. Testing, as well as design, should be modular, structured, and top-down.
Testing 20-3
Special Cases
But that leaves the question of selecting test data for a module. The designer
must cases that a program recognizes. These may include:
first list all special
• Trivial cases
• Equality cases
• Special situations
Be careful; each two-way decision doubles the number of classes since you must
testboth paths. Thus three conditional branches will result in 2x2x2
= 8 classes if
the computer always executes each branch. Limiting the size of test sets is another
important reason to keep modules short and general.
You must now separate the classes according to whether the program produces
a different result for each entry in the class (as in a table) or produces the same result
for each entry (such as a warning that a parameter is above a threshold). In the dis-
crete case, one may include each element if the total number is small or sample if the
number is large. The sample should include all boundary cases and at least one case
selected randomly. Random number tables are available in books, and random number
generators are part of most computer facilities. 6
You must be careful of distinctions that may not be obvious. For example, the
6809 microprocessor will regard an 8-bit unsigned number greater than 127 as negative;
you must consider this when using the branch instructions that depend on the Negative
(Sign) flag. You must also watch for instructions that do not affect flags, overflow in
signed arithmetic, and the distinctions between address-length (16-bit) quantities and
data-length (8-bit) quantities.
EXAMPLES
20-1. TESTING A SORT PROGRAM
The special cases here are obvious:
The other special case to be considered is one in which elements are equal.
There may be some problem here with signs and data length. Note that the array
itself must contain fewer than 256 elements. Using the instruction CLR $40 rather than
DEC $40 to modify the interchange flag means that multiple interchanges will create no
special problems.
We could check to see if the sign of the number of elements has any effect by
choosing half the test cases with elements between 128 and 255 and half with elements
between 2 and 127. We should choose the magnitudes of the elements randomly to
avoid unconscious bias which might favor small numbers, decimal (rather than hex-
adecimal) digits, or regular patterns.
these cases.
6. Emphasize generality. Each distinction and separate routine leads to more
testing.
CONCLUSIONS
Debugging and testing are the stepchildren of the software development pro-
cess. leave far too little time for them and most textbooks neglect them.
Most projects
But designers and managers often find that these stages are the most expensive and
time-consuming. Progress may be difficult to measure or produce. Debugging and
testing microprocessor software is particularly difficult because the powerful hard-
ware and software tools that can be used on larger computers are seldom available for
microcomputers.
The designer should plan debugging and testing carefully. We recommend the
:
Testing 20-6
following guidelines
1. Try to write programs that are easy to debug and test. Modular program-
ming, structured programming, and top-down design are useful techniques.
2. Prepare a debugging and testing plan as part of the problem definition.
Decide early what data you must generate and what equipment you will need.
3. Debug and test each module using top-down design.
4. Debug each module's logic systematically. Use checklists, breakpoints, and
the single-step mode. If the program logic is complex, consider using the soft-
ware simulator.
5. Check each module's timing systematically if this timing is a problem. An
oscilloscope can solve many problems if you plan the test properly. If the tim-
ing is complex, consider using a logic or microprocessor analyzer.
6. Be sure that the test data is representative. Watch for any classes of data
that the program may distinguish. Include all special and trivial cases.
REFERENCES
1. G. J. Myers. The Art of Software Testing, Wiley, New York, 1979.
R. C. Tausworthe. Standardized Development of Computer Software, Prentice-Hall,
Englewood Cliffs, N.J., Vol.1, 1977, Chapter 9; Vol. 2, 1979, Chapters 14 and 15.
E. Yourdon. Techniques of Program Structure and Design, Prentice-Hall, Englewood
Cliffs, N.J.,1975, Chapter 7.
2. F. J. Langley. "Simulating Modular Microcomputers," Simulation, May 1979, pp.
141-54.
L. A. Leventhal. "Design Tools for Multiprocessor Systems," Digital Design, Octo-
ber 1979, pp. 24-26.
F. I. Parke et al. "An Introduction to the N.mPc Design Environment," Proceedings
of the 1979 Design Automation Conference, San Diego, Ca., pp. 513-19.
3. R. Francis and R. Teitzel. "Realtime Analyzer Aids Hardware/Software Integra-
tion," Computer Design, January 1980, pp. 140-50.
5. R. A. DeMillo et al. "Hints on Test Data Selection: Help for the Practicing Pro-
grammer," Computer, April, 1978, pp. 34-41.
microprocessor spends most of its time waiting for external devices and program speed
is not a major factor.
COST OF REDESIGN
Squeezing the last bit of performance out of a program is seldom as important as
some writers would have you believe. In the first place, the practice is expensive for the
following reasons:
1. It requires extra programmer time, which is often the single largest cost in
software development.
2. It sacrifices structure and simplicity with a resulting increase in debugging and
testing time.
In the second place, the lower per-unit cost and higher performance may not
really be important. Will the lower cost and higher performance really sell more units?
Or would you do better with more user-oriented features? The only applications that
would seem to justify the extra effort and time are very high-volume, low-cost and
low-performance applications, where the cost of an extra memory chip will far out-
weigh the cost of the extra software development. For other applications, you will find
that you are playing an expensive game for no reason.
determine how much more performance or how much less memory usage is necess-
ary. If the required improvement is 25% or less, you may be able to achieve it by
reorganizing the program. If it is more than 25% you have made a basic design error;
you will need to consider drastic changes in hardware or software. We will deal first
with reorganization and later with drastic changes. Reducing memory usage is particu-
larly important if it results in a program that fits in the ROM and RAM provided by a
simple one or two-chip microcomputer. The use of such stand-alone microcomputers
can reduce hardware costs substantially in limited applications.
SAVING MEMORY
The following procedures will reduce memory usage for assembly language pro-
grams:
byte section of memory, and all RAM variables in another 100 16 -byte sec-
tion.
6. Organize data and tables so that you can address them without worrying
about address calculation carries or without any actual indexing. This will
again allow you to manipulate 16-bit addresses as 8-bit quantities.
7. Use the shift instructions to operate on bit positions at either end of a
byte.
Maintenance and Redesign 21-3
8. Take advantage of such instructions as ASL, DEC, INC, LSR, ROL, and
ROR which operate directly on memory locations without using registers.
9. Use INC or DEC to set or reset flag bits.
10. Use relative branches rather than jumps with absolute or indexed address-
ing.
11. Use the Software Interrupt instructions RTS and RTI to perform jumps
and reach subroutines they are not already being used. SWI2 should
if
13. Use algorithms rather than tables to calculate arithmetic or logical expres-
sions and to perform code conversions. This replacement may make the pro-
gram run slower.
14. Reduce the size of mathematical tables by interpolating between entries.
Here again, we are saving memory at the cost of execution time.
15. Use instructions like CMPU, CMPX, and CMPY to perform comparisons
without involving the Accumulator.
16. Employ double accumulator instructions such as ADDD, CMPD, LDD,
STD, and SUBD rather than pairs of single accumulator instructions.
17. Take advantage of the LEA instructions to perform arithmetic as well as to
calculate indirect, indexed, and relative addresses for repeated use later.
18. Use indexed addressing rather than extended addressing to handle PIAs
and other situations involving several addresses that are close together.
19. Remember on some of the registers take longer than on
that operations
some address-length registers have more single-byte
others. In particular,
operation codes than others; the number is largest for Index Register X,
next largest for the Double Accumulator and User Stack Pointer U, and
Y and the Hardware Stack Pointer. For example,
smallest for Index Register
LDX, LDD, and LDU require one-byte operation codes, whereas LDY and
LDS require two-byte codes. So, when assigning address-length registers
in your program, try to maximize the number of single-byte operation
codes that are executed. You can use TFR or EXG to move data from one
register to another.
1. Determine how frequently each program loop is executed. You can do this
by hand or by using the software simulator or other testing methods.
2. Examine the loops in the order determined by their frequency of execu-
tion, starting with themost frequent. Continue through the list until you
achieve the required reduction.
3. First, see if there are any operations that can be moved outside the loop,
such as repetitive calculations, data that can be stored in a register or in the
stack, data or addresses that can be stored on the direct page, special cases or
errors that can be handled elsewhere, etc. Note that this may require extra
initialization and memory but will save time.
5. Replace subroutines with in-line code. This will save at least a CALL and a
RETURN instruction.
6. Use the stack for temporary data storage if you can take advantage of the
automatic ordering it provides.
7. Use any of the hints mentioned in saving memory that also decrease
execution time. These include the use of 8-bit addresses, SWI, RTI, special
short forms of instructions, etc.
8. Do not even look at instructions that are executed only once. Any changes
that you make in such instructions only invite errors for no appreciable gain.
9. Avoid indexed and indirect addressing whenever possible because they
take extra time.
10. Use tables rather than algorithms; make the tables handle as much of the
tasks as possible even if many entries must be repeated.
MAJOR REORGANIZATION
If you need more than a 25% increase in speed or decrease in memory usage do
not try reorganizing the code. Your chances of getting that much of an improvement are
small unless you call in an outside expert. You are generally better off making a major
change.
Maintenance and Redesign 21-6
BETTER ALGORITHMS
The most obvious change is a better algorithm. Particularly if you are doing
sorts, searches, or mathematical calculations, you may be able to find a faster or shorter
method in the literature. Libraries of algorithms are available in some journals and from
professional groups. See the references at the end of this chapter for some important
sources.
1. A CPU with a longer word will be faster if the data is long enough. Such a
CPU will use less total memory. 16-bit processors, for example, use memory
more efficiently than 8-bit processors, since more of their instructions are one
word long.
2. Versions of the CPU may exist that operate at higher clock rates. But
remember that you will need faster memory and I/O ports, and you will have
to adjust any delay loops.
3. Two CPUs may be able to do the job in parallel or separately if you can
divide the job and solve the communications problem.
4. A specially microprogrammed processor may be able to execute the same
program much faster. The cost, however, will be much higher even if you
use an off-the-shelf emulation.
5. You can make tradeoffs between time and memory. Lookup tables and func-
tion ROMs will be faster than algorithms, but will occupy more memory.
REFERENCES
Carnahan, B., et al. Applied Numerical Methods, Wiley, New York, 1969.
Chen, "Automatic Computation of Exponentials, Logarithms, Ratios, and Square
T. C.
Roots," IBM Journal of Research and Development, Volume 18, pp. 380-388, July 1972.
Collected Algorithms from ACM, ACM Inc., P.O. Box 12105, Church Street Station,
New York, 10249.
Despain, A. M. "Fourier Transform Computers Using CORDIC Iterations," IEEE
Transactions on Computers, October 1974, pp. 993-1001.
Edgar, A. D. and S. C. Lee. "FOCUS Microcomputer Number System," Communica-
tions of the ACM, March 1979, pp. 166-177.
Hwang, K. Computer Arithmetic, Wiley, New York, 1978.
Knuth, D. E. The Art of Computer Programming, Volume I : Fundamental Algorithms; The
Art of Computer Programming, Volume 2: Seminumerical Algorithms; The Art of Computer
Programming, Volume 3: Sorting and Searching, Addison-Wesley, Reading, Mass. 1967-
1969.
Luke, Y. L. Algorithms for the Computation of Mathematical Functions, Academic Press,
New York, 1977.
Schmid, H. Decimal Computation, Wiley-Interscience, New York, 1974.
New methods for performing arithmetic operations on computers are often discussed in
the triennial Symposium on Computer Arithmetic. The Proceedings (starting with
1969) are available from the IEEE Computer Society, 10662 Los Vaqueros Circle, Los
Alamitos, Calif. 90720.
V
6809 Instruction Set
Chapter 22 and the appendices that follow it comprise a total reference for the
6809 instruction set. Chapter 22 describes each instruction in some detail; the appen-
dices summarize that information and also provide material on indexed and indirect
addressing modes.
22
Descriptions of Individual
6809 Instructions
sequence whose execution has results equivalent to those of the 6800 instruction.
These instructions are predefined macro calls and may not be available on all 6809
assemblers.
A description generally includes a diagram of the execution of the instruction.
Since the 6809 microprocessor has so many addressing modes, we have not attempted
to describe all the modes for each instruction.
PSHS B
ADDA ,S+
This instruction adds the two accumulators and stores the result in Accumulator A. It is
included in the assembler to allow source compatibility between the 6800 and the 6809
microprocessors.
22-2 6809 Assembly Language Programming
ABX 3A 3 1
Add the contents of Accumulator B to those of Index Register X. Store the result
in Index Register X. ABX treats the contents of B as an unsigned number.
Data
Memory
H I N
CCR
X
< XX
ppqq + OOxx
PP qq
Program
Y Memory
U
PC mm mm mmmm + 1 3A mmmm
DP mmmm + 1
mmmm + 2
ABX mmmm + 3
Suppose xx = 84, 6 and ppqq = 1097 16 . After the processor executes the ABX
instruction, Index Register X will contain 1B1 1
16 :
leave 28E0 16 in X, but LEAX B,X will place 27E0 16 in X. LEAX B,X should be used in
Descriptions of Individual 6809 Instructions 22-3
most situations; however, when program space or execution time is at a premium, the
shorter, faster ABX can replace it. Remember, though, that when you replace LEAX
B,X with ABX, you may have to relocate the memory area being addressed by the index
register.
ABX affects no flags; it is meant to manipulate addresses rather than data. This
isone of the few 6809 instructions that lack generality; it applies to only two specific
registers — B and X — and cannot be extended to any others. The instruction is
included in the 6809 instruction set for compatibility with the 6801 processor.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycle* Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ADCA 89 2 2 99 4 2 B9 5 3 A9 4+ 2+
ADCB C9 2 2 D9 4 2 F9 5 3 E9 4+ 2+
This instruction adds the contents of a memory location and the contents of the
Carry flag to the contents of Accumulator A or B. The result is stored in the specified
accumulator.
Consider performing an addition with Carry using immediate data and Accumula-
tor A.
E F H 1 N z V c
ccr| X X X X x r
XX
°{:
x
PC mm mm
DP
ADCA #$7C
Suppose that xx = 3A, 6 and C = 1. After the processor executes the instruction ADCA
#$7C, Accumulator A will contain B7, 6 .
22-4 6809 Assembly Language Programming
3A = 0011 1010
7C = 0111 1100
Carry= 1_
¥ 1 =1, set V to 1
-»- 1 sets N to 1
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ADDA 8B 2 2 9B 4 2 BB S 3 AB 4+ 2+
ADDB CB 2 2 DB 4 2 FB 5 3 EB 4+ 2+
ADDD C3 4 3 D3 6 2 F3 7 3 E3 6+ 2+
ADDA and ADDB add the contents of a memory location to the value in
Accumulator A or Accumulator B, placing the sum in the designated accumulator.
ADDD adds the contents of a memory word (two contiguous bytes) to the value in the
double accumulator, placing the result in the double accumulator.
CCR
XX
{:
X
PC mm mm
DP dd
ADDA $40
Descriptions of Individual 6809 Instructions 22-5
24 0010 0100
8B 1000 1011
1010 1111- -+ Nonzero result resets Z to
-»- No Carry from bit 3 resets H to
~1 \
V = 0, No Carry from bit 6 or 7, reset V to
-*- Bit 7 sets N to 1
-» No Carry, reset C to
ADDA and ADDB are the usual single-byte addition instructions; they are also
used to add the least significant bytes of multibyte addends greater than 16 bits.
ADDD, which we will describe next, is available for 16-bit addition.
Now consider the ADDD instruction. This instruction adds the contents of two
memory locations Double Accumulator D. The double accumulator's high-order
to the
byte is Accumulator A; its low-order byte is Accumulator B. The number to be added
has its high-order byte in the first memory address and its low-order byte in the subse-
quent memory address.
We will illustrate the ADDD instruction using immediate addressing.
E F H 1 N z V c
ccrI X x X
*l
ADDD #$1011
22-6 6809 Assembly Language Programming
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Byte* Code Cycles Bytes Code Cycles Bytes
ANDA 84 2 2 94 4 2 B4 5 3 A4 4+ 2+
ANDB C4 2 2 D4 4 2 F4 5 3 E4 4+ 2+
ANDCC 1C 3 2
E F H I N Z v C
CCR
ANDB ,X
FC - 1111 1100
13 « Q001 QQ11
0001 0000- Nonzero result, Z reset to
V is cleared regardless of the result
Bit 7 resets N to
position.
T. The Zero flag can then be used as a branch condition with the instruction
BNE or BEQ. For example,
ANDA *%00001000
BNE BIT1 BRANCH IF BIT 3 OF A IS I
ANDA H00010000
BEQ BITO BRANCH IF BIT A OF A 13
1
E F h i n z v c
CCR X
I
I*
oi"
\b
mm mm
DP
ANDCC #$BF
All flags may be affected by the ANDCC operation. It clears all the flags that are
logically ANDed with 'O's, while leaving the other flags unchanged. The following
masks can be used to clear individual flags:
Of course, 'O's in more than one bit position will clear more than one flag at a
time. However, only a few possibilities are really useful. In particular, we should note:
ple-precision addition — there is, of course,no carry into the least significant bytes, so
the Carry must be cleared originally. The Carry must also be cleared initially for multi-
ple-precision binary subtraction, to signify that there is no borrow required from the
least significant bytes. The CLR instruction also clears the Carry flag.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ASL 08 6 2 78 7 3 68 6+ 2+
ASLA 48 2 1
ASLB 58 2 1
±
{{
Program
Memory
mm mmmm + 48 mmmm
mm 1
j
mmmm + 1
DP
ASLA
Carry Accumulator A
0111 1010
/
ASLA 1111 01 00 •» Nonzero result, reset Z to
~1 4
V 1 = 1. set V to 1
H is undefined
22-10 6809 Assembly Language Programming
The Overflow flag (V) is loaded with the Exclusive-OR of bits 7 and 6 of the origi-
nal operand; these bit values are the same as those of the resulting Carry (C) and Sign
(N) flags. Common uses of ASL include simple multiplication (by small integers such
as 2 or 4), serial-to-parallel conversion, and scaling. Note that a single ASL instruc-
tion multiplies its operand by 2. This instruction is the same as Logical Shift Left (LSL).
An ASL operation on a memory location is exactly like the accumulator opera-
tion.There is, of course, some difference in object code size and execution time,
depending on the addressing mode.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ASR 07 6 2 77 7 3 67 6+ 2+
ASRA 47 2 1
ASRB 57 2 1
E F H I N Z V C
CCR
ppqq
r.
X
U pp qq
PC mm mm
DP
ASR ,U+
Suppose ppqq = 0134 16 and the contents of location 0134 16 are CB 16 . Executing an
ASR ,U+ instruction will change the contents of memory location 0134 16 to E5, 6 The
.
1100 1011
ASR 11100101
Nonzero result, reset Z to
-* Bit 7 sets N to 1
H is undefined
While the 6809's ASR instruction does not affect the Overflow flag (V), those of
the 6800/01/02/03/08 processors do.
An arithmetic right shift preserves the value of the most significant bit (or sign
bit); it can thus be used for scaling twos complement numbers, since it retains their
signs. The ASR instruction is frequently used in division routines.
BCC 24 3 2
This instruction is the same as BRA except that it causes a branch only if the Carry
flag is 0. If the Carry flag is 1, the processor continues to the next instruction in the nor-
mal sequence.
Consider the following section of a program:
-B€C NEXT
Ar>DA #$7F
C-0
NEXT CLRA
BCS 25 3 2
This instruction is the same as BRA except that it causes a branch only if the Carry
flag is 1. If the Carry flag is 0, the processor continues to the next instruction in the nor-
mal sequence.
Consider the following section of a program:
-B€S NEXT
ANDA #$7F
c
NEXT CLRA
When used after a subtract or compare on unsigned binary values, this instruction could
be called "branch if the register was higher or the same as the memory operand;" in
fact, the 6809 assembler will accept the mnemonic BHS for this instruction.
BEQ 27 3 2
This instruction is the same as BRA except that it causes a branch only if the Zero
flag is 1. If the Zero flag is 0, the processor continues to the next instruction in the nor-
mal sequence.
Consider the following section of a program:
NEXT
ANPA #$7F
Z =
il
NEXT CLRA
After executing BEQ, the processor next executes:
that the Zero flag is set to 1 if the most recent result was zero. When
Remember
BEQ used after a subtract or compare, branching will occur only if the values com-
is
BGE 2C 3 2
This instruction is the same as BRA except that it causes a branch only if:
If neither of these conditions is true, the processor continues to the next instruc-
tion in the normal sequence. The branch conditions can be simplified logically to the
form N© - 0.
-bce NEXT
ANDA #$7F
n © v- o N © V
NEXT CLRA
1. CLRAifN0V = O.
2. ANDAifN©V - 1.
The conditions have the following significance if a CMP (compare) instruction
immediately precedes the branch:
1. N = and V = if the result of CMP is positive (N = 0), and twos comple-
ment overflow did not occur (V = 0).
2. N = and V = 1 if the result appears to be negative (N
1 = 1), but the sign
was changed by twos complement overflow (V = 1).
BGT 2E 3 2
This instruction is the same as BRA except that it causes a branch only if the Zero
22-14 6809 Assembly Language Programming
flag is and:
If this condition is not true, the processor continues to the next instruction in the
normal sequence. The branch condition can be simplified logically to the form
Z + (N © V) - 0.
KiT NEXT
AlfDA #$7F
Z +(N V) - Z + (N ® V)
-NSXT CLRA
1. CLRAifZ +(N© V) - 0.
2. ANDAifZ+(N© V) - 1.
negative (N — 1), but its sign was changed by twos complement overflow (V
- 1).
So the branch occurs if the result is is either a true positive number
not zero and
(unaffected by overflow) or a false negative number (affected by overflow). This
analysis assumes that all numbers are in twos complement form. BGT thus provides a
twos complement Greater Than branch; alternatives are
BHI 22 3 2
This instruction is the same as BRA except that it causes a branch only if the Zero
flag and the Carry flag are both 0. If either flag is not zero, the processor continues to the
next instruction in the normal sequence.
Descriptions of Individual 6809 Instructions 22-15
-BUI NEXT
AIIDA #$07
Z + C z + c
NEXT CLRA
1. CLRA if the Carry flag and the Zero flag are both 0.
1. C = and Z = if the result of CMP is not zero and the operation did not
BHI differs from BHS (BCC) after a comparison only if the result is zero; BHS
causes a branch in that case, while BHI does not. BHI thus provides an unsigned Greater
Than branch; alternatives are:
and the other instructions listed do not affect the Carry flag.
BHS 24 3 2
This instruction is exactly the same as BCC. The alternative mnemonic reflects
the fact that the condition has the following significance if a CMP (compare) instruction
immediately precedes the branch:
1. C = if the operation did not require a borrow. That is, the unsigned number
in the register was greater than or equal to the unsigned number to which it
was compared.
2. C = 1 if the operation required (produced) a borrow. That is, the unsigned
number in the register was less than the unsigned number to which it was
compared.
22-16 6809 Assembly Language Programming
BHS (BCC) causes a branch if the operation did not require a borrow. BHS (BCC) thus
provides an unsigned Greater Than or Equal To branch; alternatives are:
Object No. of No. ol Objact No. of No. of Objact No. of No. of Objact No. of No. of
Cad* Cyeloa Bytaa Coda Cyclaa Bytaa Coda Cyclaa Bytaa Coda Cyclaa Bytaa
BITA B5 2 2 95 4 2 B5 5 3 A5 4+ 2+
BITB C5 2 2 D5 4 2 F5 5 3 E5 4+ 2+
E F H 1 N z V c
ccr| X X
1
X
< XX
PC mm mm
DP
BITA $1641
Accumulator A will still contain A6 and memory location 1641 16 will still contain E0 I6
l6 ,
Descriptions of Individual 6809 Instructions 22-17
V is always cleared.
BLE 2F 3 2
This instruction is the same as BRA except that it causes a branch only if:
If none of these conditions is true, the processor continues to the next instruction in the
normal sequence. The branch conditions can be simplified logically to the form
Z + (N V) = 1.
Consider the following section of a program:
-BtE NEXT
AHDA #$7F
Z + (N © V) - 1 Z + (N © V) -
NFXT ^ CLRA
After executing BLE, the processor next executes:
1. CLRA if Z + (N® V) = 1.
2. ANDA if Z + (N V) = 0.
So the branch occurs the result is zero, a true negative (unaffected by overflow), or a
if
BLO 25 3 2
This instruction is exactly the same as BCS. The alternative mnemonic reflects the
fact that the condition has the following significance if a CMP (compare) instruction
immediately precedes the branch:
was compared.
So BLO (BCS) causes a branch if the operation required a borrow. BLO (BCS) thus pro-
vides an unsigned Less Than branch; alternatives are:
BLS 23 3 2
This instruction is the same as BRA except that it causes a branch jf either the
Carry flag is 1 or the Zero flag is 1. If neither flag is 1, the processor continues to the next
instruction in the normal sequence.
Consider the following section of a program:
"BtS NEXT
AlfDA #$7F
c + z = 1 c + z
NEXT CLRA
Descriptions of Individual 6809 Instructions 22-19
2. ANDA if the Carry flag and the Zero flag are both 0.
BLS differs from BLO comparison only if the result is zero; BLS causes a
(BCS) after a
branch in that case, while BLO
(BCS) does not, since no borrow is required if the result
is zero. BLS thus provides an unsigned Less Than or Equal To branch; alternatives are:
The BLS instruction is generally not useful after INC/DEC, LD/ST, TST/CLR/COM:
CLR always resets the Carry flag to 0, COM always sets the Carry flag to 1 , and the other
instructions listed do not affect the carry flag.
BLT 2D 3 2
This instruction is the same as BRA except that it causes a branch only if:
If neither of these conditions is true, the processor continues to the next instruc-
tion in the normal sequence. The branch conditions can be simplified logically to the
formNe V = 1.
-Btr NEXT
ArfDA #$7F
N © V = 1 N ®V -
NEXT ^CLRA
1. CLRA if N© V = 1.
2. ANDAifN0V = O.
22-20 6809 Assembly Language Programming
BMI 2B 3 2
This instruction is the same as BRA except that it causes a branch only if the Sign
flag is 1. If the Sign flag is 0, the processor continues to the next instruction in the nor-
mal sequence.
Consider the following section of a program:
-BMI NEXT
AC DA #$7F
NEXT CLRA
BMI is used to test the value in bit position 7; that bit position is often used for
parity, status indicators, or peripheral status bits. Used
an operation on twos
after
complement binary values, this instruction will "branch if the result is minus," but the
signmay be invalid due to twos complement overflow.
BNE 26 3 2
This instruction is the same as BRA except that it causes a branch only if the zero
Descriptions of Individual 6809 Instructions 22-21
mal sequence.
Consider the following section of a program:
-er»E NEXT
AtyDA #$7F
Z '
NEXT CLhA
a subtract or compare operation on any binary values, this instruction will "branch if the
register is not equal to the memory operand."
BPL 2A 3 2
This instruction is the same as BRA except that it causes a branch only if the Sign
flag is 0. If the Sign flag is 1 , the processor continues to the next instruction in the nor-
mal sequence.
Consider the following section of a program:
-BPL NEXT
ANDA #$7F
N
NEXT CLRA
BRA 20 3 2
. 1
BRA always causes a branch to the specified address by placing that address in the
Program Counter. The specified address is the sum of the current value of the program
counter (after the processor has fetched the BRA instruction from memory) and the dis-
placement. The displacement is an 8-bit twos complement number contained in the sec-
ond byte of the instruction
Data
Memory
E F H 1 N Z V c
CCRJ
1
•{:
X
Program
Y Memory
U
PC mm mm 20 mmmm
DP 23 mmmm + 1
mmmm + 2
mmmm + 3
BRA *+$25
NEXT CLRA
After executing BRA, the processor always executes CLRA next. It will never execute
the ANDA instruction unless a branch or jump instruction elsewhere in the program
transfers control to that instruction.
The overall effect of a BRA instruction is:
PC = PC + 2 + disp
The extra factor of 2 is the result of the 2 bytes occupied by the BRA instruction itself.
Since the displacement is an 8-bit twos complement number with the range:
where * refers to the value of the Program Counter at the start of the instruction.
Descriptions of Individual 6809 Instructions 22-23
BRA does not affect any flags or any registers except the program counter (its
The final value of the program counter is its original value plus 7 (5 more
than its normal value at the end of a 2-byte instruction).
2. FE, 6
The final value of the program counter is the same as its original value,
since FE 16 = —2 when considered as an 8-bit twos complement number. This
displacement results in an endless loop.
3. FA 16
The final value of the program counter is its original value minus 4—6 less
than its normal value at theend of a 2-byte instruction. FA 16 - -6 when
considered as an 8-bit twos complement number.
BRN 21 3 2
BRN is the same as BRA except that it never causes a branch. Thus BRN is really
a no-operation; that is, control always passes to the next instruction. Note BRN is a
that
2-byte no-operation, since the second byte contains the displacement that will never be
used. BRN makes the set of branches logically complete. Typical usage of BRN is as a
byte filler, or it may be used to fine-tune delay routines. See the NOP instruction
description for a discussion of uses for no-operations.
BSR 8D 7 2
This instruction is the same as BRA except that it saves the contents of the Pro-
gram Counter (after the 2-byte BSR instruction has been fetched) in the Hardware
Stack.
BSR saves the return address in the Hardware Stack as follows:
1. Decrement the Hardware Stack Pointer and store the low-order byte of the
program counter at that address.
22-24 6809 Assembly Language Programming
2. Decrement the hardware Stack Pointer again and store the high-order byte of
the Program Counter at that address.
Data
Memory
E F H I N Z V C
CCR
°{:
X
U
S XX XX
PC mm mm
DP
BSR *+$25
Suppose xxxx = DE30 16 and mmmm = 1024 16 After the execution of BSR
.
*+$25 the stack pointer S will contain DE2E 16 ,the Program Counter will contain
1049 16 location
, DE2E 16 will contain DE2F will contain 26 16
10 16 and location
, .
BSR SUBR
ANDA #$7F
SUBR CLRA
RTS
After executing BSR, the processor always executes CLRA next just as after BRA.
However, it also saves the address of the ANDA instruction at the top of the hardware
stack. Later an RTS instruction can conclude the subroutine and transfer control back to
the return address at the top of the hardware Stack. Thus control passes from the BSR
instruction to the subroutine and back to the ANDA instruction.
Descriptions of Individual 6809 Instructions 22-25
BVC 28 3 2
BVC is the same as BRA except that it causes a branch only if the Overflow flag is
0. If the Overflow flag is 1, the processor continues to the next instruction in the normal
sequence.
Consider the following section of a program:
-bvc NEXT
AIIDA #$7F
NEXT CIRA
BVS 29 3 2
BVS is the same as BRA except that it causes a branch only if the Overflow flag is
1. If the Overflow flag is 0, the processor continues to the next instruction in the normal
sequence.
Consider the following section of a program:
-BVS NEXT
AhDA
v = i V =
NEXT CLRA
Used after an operation on twos complement binary values, this instruction will
"branch if there was an overflow." This instruction
is also used after ASL or LSL to
detect binary floating-point normalization.
22-26 6809 Assembly Language Programming
This instruction subtracts Accumulator B from Accumulator A and sets the flags accor-
dingly. It is handled by the 6809 assembler to allow source compatibility with the 6800
processor. The contents of the accumulators do not change.
The 6809 assembler translates this 6800 instruction into the equivalent 6809
instruction ANDCC#%11111110 — that is, into an instruction that clears the least sig-
nificant bit of the Condition Code Register (the Carry flag). CLC does not affect any
other flags or registers. Note that the CLR instruction also clears the Carry flag.
Condition Code Register (the regular interrupt mask bit). This instruction enables the
6809's regular interrupt — that is, the 6809 will respond to the interrupt request control
line. No other registers or flags are affected. Note that you can also clear the interrupt
mask as part of the execution of the CWAI instruction.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
CLR OF 6 2 7F 7 3 6F 6+ 2+
CLRA 4F 2 1
CLRB 5F 2 1
Data
Memory
CCR
•{: XX
X
Program
Y Memory
U
PC mm mm 5F mmmm
DP mmmm + 1
mmmm + 2
mmmm + 3
CLRB
Suppose that Accumulator B contains 43 )6 After the processor executes the instruction
.
CLRB, Accumulator B will contain 00, 6 In addition, the Sign, Overflow, and Carry flags
.
The 6809 assembler translates this 6800 instruction into the equivalent 6809
instruction ANDCC *% 11111101 — that is,into an instruction that clears bit 1 of the
Condition Code register (the Overflow flag). No other flags or registers are affected. The
Overflow flag is also cleared by many other instructions, including AND, BIT, CLR,
COM, EOR, LD, OR, ST, and TST.
22-28 6809 Assembly Language Programming
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Coda Cycles Byte* Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
CMPA 81 2 2 91 4 2 B1 5 3 A1 4+ 2+
CMPB CI 2 2 D1 4 2 F1 5 3 E1 4+ 2+
CMPD 10 83 5 4 10 93 7 3 10 B3 8 4 10 A3 7+ 3+
CMPS 11 8C 5 4 11 9C 7 3 11 BC 8 4 11 AC 7+ 3+
CMPU 11 83 5 4 11 93 7 3 11 B3 8 4 11 A3 7+ 3+
CMPX 8C 4 3 9C 6 2 BC 7 3 AC 6+ 2+
CMPY 10 8C 5 4 10 9C 7 3 10 BC 8 4 10 AC 7+ 3+
There are two forms of this instruction — an 8-bit form and a 16-bit form. The
8-bitform is associated with Accumulators A and B. The 16-bit form is associated with
the 16-bit registers D, X, Y, U, and S. This instruction subtracts the contents of the
selected memory location from the contents of the specified register and sets the Condi-
tion flags accordingly. Neither the contents of the memory location nor the contents of
the register are changed. The Carry flag represents a borrow.
Let us begin with the 8-bit case using immediate addressing and Accumulator A.
CCR
XX
»<:
X
PC mm mm
DP
CMPA #$18
Accumulator A will still contain F6'1616 , but the flags will be modified as follows:
F6 - 1111 0110
Twos complement of 1 8 = 1110 1000
1101 1 1 10- -
Nonzero result resets Z to
flVUO, reset V to
*- Bit 7 sets N to 1
-^ No borrow resets C to
H is undefined.
Note that C is the complement of the resulting carry since it represents a borrow. Com-
pare instructions are most frequently used to set flags before the execution of branch
instructions. Note that the half-carry flag (H) is undefined after the 8-bit instruc- CMP
tion.
Now consider the 16-bit case. The execution of the two-byte compare is the same
as for the one-byte compare illustrated above with the exception that a 16-bit com-
parison takes place rather than an 8-bit comparison. We will illustrate CMPX using
extended addressing.
h i n z v c
CCR
f.
x pp qq
PC mm mm
DP
CMPX $A4F1
Suppose that ppqq = 1AB0 I6 , xx (the contents of memory location A4F1) = 1B 16 and
,
CMPX $A4F1, Index Register X and memory will be unchanged but the Sign, Zero,
Overflow, and Carry flags will be modified as follows.
22-30 6809 Assembly Language Programming
-•-0 V = 0, reset V to
-Bit 15 sets N to 1
H flag is unaffected.
Notice that C is the complement of the resulting carry, just as in the CMPA
instruction. The flags are affected by the complete 16-bit operation, not by the two 8-bit
operations separately. The similar instructions (CMPD, CMPS, CMPU, and CMPY) all
require 2-byte operation codes while CMPX requires only one. This means that pro-
grammers should prefer Index Register X over Index Register Y and the stack pointers
to minimize the memory usage and execution time of their programs.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
COM 03 6 2 73 7 3 63 6+ 2+
COMA 43 2 1
COMB 53 2 1
a 0, and each with a 1. We will illustrate the COM instruction using the indirect
indexed mode with zero offset from Index Register X.
H I
CCR
•C
X pp qq
Program
Y Memory
U 63 mmmm
S 94 mmmm + 1
PC mm mm mmmm + 2
DP mmmm + 3
COM [,X]
Descriptions of Individual 6809 Instructions 22-31
Suppose that the contents of Index Register X are 0100i 6 and that memory locations
0100 and 0101 contain 01 13i 6 If the contents of memory location 0113 are 23 16 then
. ,
after the processor executes the instruction COM [,X], memory location 0113 will be
changed to DC 16 .
23 = 0010 0011
Ones complement of 23 = 1 101 1 100- -* Nonzero result resets Z to
V is reset to always
Bit 7 sets N to 1
C is set to 1 always
CWAI 3C 20 2
This instruction logically ANDs the contents of the following byte of program
memory with the contents of the Condition Code Register, saves all the user registers in
the Hardware Stack, and halts execution until an external interrupt occurs.
Data
Memory
10 XX xxxx ssss - C
aa ssss - B
bb ssss - A
ii ssss - 9
cc ssss - 8
dd ssss - 7
ee ssss - 6
ccr| x ff ssss - 5
99 ssss - 4
hh ssss - 3
aa mm ssss - 2
D )
i: bb mm + 2 ssss - 1
cc dd >- ssss
ee ff
Program
99 hh
) Memory
ss ss
mm mm 3C mmmm
DP ii
s
BF mmmm + 1
Remember that clearing aninterrupt mask enables the interrupt from that source.
After the processor has saved the status of the system in the Hardware Stack as
shown in the diagram above, it halts execution until it receives an interrupt. Note that
the contents of the Hardware Stack Pointer are not stacked. When an interrupt occurs,
the interrupt mask bits are set to 1 and the processor jumps to the address in the
appropriate interrupt vector.
This instruction is used to synchronize the CPU with external processes.
CWAI does not tri-state the system busses. A fast interrupt may enter its interrupt
handler with the entire machine state saved; RTI will automatically restore the
entire machine state after testing the E bit of the recovered CCR.
DAA 19 2 1
ADDA $15E1
DAA
binary result. The Carry be reset to since there was no carry; the Overflow flag
flag will
is undefined; the Zero flag is reset to since the result is not zero; and bit 7 sets N to 1.
This is the only instruction that requires the Half-Carry flag (H); its value is needed to
determine if a Carry occurred from the less significant digit.
The Sign and Zero flags are modified to reflect the statuses they represent. The
Overflow flag is destroyed and the Carry flag is set or reset as it should be by a hypotheti-
cal BCD addition. That is, the Carry flag is set if the BCD sum of the more significant
digits produced a carry.
Correction factors of 6 are added to each 4-bit digit of Accumulator A under the
following conditions:
This instruction makes sense only after a binary addition instruction (ADC or
ADD) ;the combinations ADC A, DA A or ADDA, DAA are decimal addition instruc-
tions that operate on BCD data and generate BCD results.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Cod* Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
DEC OA 6 2 7A 7 3 6A 6+ 2+
DECA 4A 2 1
DECB 5A 2 1
H I N
CCR
{:
X
Program
Y Memory
U
S
PC 5A mmmm
DP mmmm + 1
mmmm + 2
mmmm + 3
DECB
3A = 0011 1010
Ones complement of 1 = 1111 1111
0011 1001 -*- Nonzero result resets Z to
1
»- 1 V 1 = 0, V is reset to
*- Bit 7 resets N to
Carry is not affected
The fact that DEC does not affect the Carry flag is quite important; it allows the pro-
grammer to use DEC (or INC) to count iterations of a loop that is performing multi-
ple-precision arithmetic. The Carry flag is essential in such a loop to transfer informa-
tion (carries or borrows) from one iteration to the next. Decrementing a register or
memory location that contains zero produces a result of FF 16 but does not set the Carry
flag.
The 6809 assembler translates this 6800 instruction into the equivalent 6809
instruction LEAS — 1,S — that is, into an instruction that subtracts1 from the Hard-
ware Stack Pointer. Note that DES provides a 16-bit decrement that does not affect the
flags.
The 6809 assembler translates this 6800 instruction into the equivalent 6809
instruction LEAX — 1,X — that is, into an instruction that subtracts 1 from Index
Register X. Note that DEX provides a 16-bit decrement that affects only the Zero flag.
The 6809 assembler translates this 6800-like instruction into the equivalent 6809
instruction LEAY — 1,Y — that is, into an instruction that subtracts 1 from the contents
of Index Register Y. Note that DEY provides a 16-bit decrement that affects only the
Zero flag.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
EORA 88 2 2 98 4 2 B8 5 3 A8 4+ 2+
EORB C8 2 2 D8 4 2 F8 5 3 E8 4+ 2+
Descriptions of Individual 6809 Instructions 22-35
E F H 1 N z V c
CCR| X X ppqq + 60
1
ppqq + 61
•<: XX
X pp qq
PC mm mm
DP
EORB [$60,X]
After the processor executes the instruction EORB [$60, X] Accumulator B will contain
43 16 .
E3 = 1110 0011
AO = 1010 0000
0100 001 1
"-Nonzero result resets Z to 0.
Bit 7 resets N to
C isnot affected
V is cleared.
EXG 1E 8 2
This instruction exchanges the contents of one 8- or 16-bit register with another.
The subsequent byte of immediate data determines which registers are exchanged. Note
22-36 6809 Assembly Language Programming
that registers may only be exchanged with registers of like size, that is 8-bit with 8-bit
and 16-bit with 16-bit.
We will illustrate the execution of the EXG A,B instruction.
Data
Memory
E F H I N Z V C
CCR
XX
X
yy b
Program
Y Memory
U
S
PC mm mm 1E mmmm
DP 89 mmmm + 1
mmmm + 2
mmmm + 3
EXG A.B
EXG is, — for instance, EXG A,B and EXG B,A are the same
of course, symmetric
operation. Note that all EXG instructions require two bytes of memory — one for the
operation code and one for a post byte (immediate data) to specify which registers are to
be exchanged. Be careful of the fact that some EXG instructions are meaningless
(undefined register codes), while others are illegal (exchanging registers with different
lengths).
Descriptions of Individual 6809 Instructions 22-37
I i i i
I .
RE G1
- .
REG2 POST BYTE
D OOOO PC 0101 5
X 0001 1 A 1000 8
Y 0010 2 B 1001 9
U 0011 3 CCR 1010 A
S 0100 4 DP 1011 B
Hexadecimal: 1E 8 9
Bits through 3 of the immediate byte of the instruction define one register, while bits 4
through 7 define the other. The condition codes are not affected unless one of the
registers is the Condition Code Register itself (CCR).
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycle* Bytes Code Cycles Bytes Code Cycles Bytes
INC OC 6 2 7C 7 3 6C 6+ 2+
INCA 4C 2 1
INCB 5C 2 1
This instruction adds one to the contents of the specified 8-bit accumulator or byte
of memory.
Consider incrementing a memory location addressed by indirect indexed mode
with Accumulator A offset from Index Register X.
22-38 6809 Assembly Language Programming
E F H 1 N z V c
X X X ppqq + rr
1 1
ppqq + rr + 1
rr
•{:
X pp qq
Program
Y Memory
U
PC mm mm 6C mmmm
DP 96 mmmm + 1
mmmm + 2
mmmm + 3
INC [A,X)
If ppqq - 150A 16 , rr = FE l6 ,
sstt = 25E4 16 and xx = C0 16 then after the processor
, ,
executes the instruction INC [A,X], will have changed the contents of memory loca-
it
co = 1 1 oo oooo
1 = oooo 0001
1100 0001 -Nonzero result resets Z to
0V0=0, reset V to
•Bit 7 sets N to 1
C is not affected.
The fact that INC does not affect the Carry flag is quite important; it allows the
programmer to use INC (or DEC) to count iterations of a loop that is performing
multiple-precision arithmetic. The Carry flag is essential in such a loop to transfer
information (carries or borrows) from one iteration to the next. Incrementing a register
or memory location that contains FF 16 produces a result of 00 16 but does not set the
Carry flag; however, it does set the Zero flag.
INC and DEC are commonly used to count occurrences of events or numbers of
iterations. INC is more commonly (and more logically) used for event counting, while
DEC is more commonly used for looping since the Zero flag is then available as a con-
venient exit condition.
After increments of unsigned values, only BNE and BEQ branches will behave
consistently. When the operands are twos complement values, all signed branches
function correctly.
Note that this instruction does not apply to the Double Accumulator D. Thus,
the only accumulator forms implemented are INCA and INCB.
Descriptions of Individual 6809 Instructions 22-39
The 6809 assembler translates this 6800 instruction into the equivalent 6809
instruction LEAS 1,S — that is, into an instruction that adds 1 to the contents of the
Hardware Stack Pointer. Note that INS performs a 16-bit increment that does not affect
any flags.
The 6809 assembler translates this 6800-like instruction into the equivalent6809
instruction LEAY 1,Y — that is, an instruction that adds 1 to the contents of Index
into
Register Y. Note that INY performs a 16-bit increment that affects only the Zero flag.
JMP OE 3 2 7E 4 3 6E 3+ 2+
Data
Memory
E F H I N Z V C
CCR
<:
X
PC mm mm
DP
JMP [3A05]
If, for example, rrss = D1E5, then after the processor executes the instruction
JMP [$3A05],the Program Counter will contain D1E5 and execution will continue from
that point.
The terminology here is somewhat confusing (as on most computers) — JMP
with extended addressing transfers control to the extended address, not to its contents.
So JMP with extended addressing is similar to other instructions (such as LD) with
immediate addressing. For example, JMP $3E08 transfers control to (loads the program
counter with) 3E08 16 not the contents of that address. JMP with indexed addressing is
,
theJMP instruction will perform an indexed jump into a table of addresses starting at
JTABL, with the index given by the contents of memory addresses INDEX and
INDEX+1. Some part of the program preceding LDX must double the contents of
INDEX and INDEX + 1 to account for the fact that all addresses occupy two bytes.
Note the distinction from the instruction sequence
In this sequence, the JMP instruction will transfer control to the appropriate position in
JTABL, index given by the contents of memory addresses
the table (base address
INDEX and INDEX+1). That position must contain a JMP or branch instruction
transferring control to the appropriate routine, rather than just the address of the
routine as in the earlier case.
Descriptions of Individual 6809 Instructions 22-41
JSR 9D 7 2 BD 8 3 AD 7+ 2+
Jump unconditionally to the specified memory address, saving the old value of the
Program Counter on the hardware Stack.
We will illustrate the execution of JSR with extended addressing.
F h i n z v c
CR
I
n/
(b
Y
U
S ss ss
PC mm mm
DP
JS R $ E1A 3
here as with JMP; JSR with extended addressing transfers control to the extended
address, not to its contents. All the indexed modes operate similarly, as if one level of
indirection had been removed.
LBCC 10 24 5(6} 4
LBCC is the same as LBRA except that it branches under the same condition as
does BCC. LBCC is a 4-byte instruction using 16-bit relative addressing while BCC is a
2-byte instruction using 8-bit relative addressing. See LBRA and BCC for details on the
operation of LBCC.
LBCS 10 25 5(6) 4
LBCS is the same as LBRA except that it branches under the same condition as
does BCS. LBCS is a 4-byte instruction using 16-bit relative addressing while BCS is
only a 2-byte instruction using 8-bit relative addressing. See LBRA and BCS for details
on the operation of LBCS.
LBEQ 10 27 5(6) 4
LBGE 10 2C 5(6) 4
LBGE is the same as LBRA except that it causes a branch under the same condi-
tion as does BGE. LBGE is a 4-byte instruction using 16-bit relative addressing while
Descriptions of Individual 6809 Instructions 22-43
BGE is a 2-byte instruction using 8-bit relative addressing. See LBRA and BGE for
LBGT 10 2E 5(6) 4
LBGT is the same as LBRA except that it causes a branch under the same condi-
tion as does BGT. LBGT is a 4-byte instruction using 16-bit relative addressing while
BGT is a 2-byte instruction using 8-bit relative addressing. See LBRA and BGT for
LBHI 10 22 5(8) 4
LBHI is the same as LBRA except that it causes a branch under the same condi-
tions as does BHI. a 4-byte instruction using 16-bit relative addressing while
LBHI is
BHI is a 2-byte instruction using 8-bit relative addressing. See and BHI for details LBRA
on the operation of LBHI.
LBHS 10 24 5(6) 4
LBHSthe same as LBRA except that it causes a branch under the same condi-
is
tion as does BHS. LBHS is a 4-byte instruction using 16-bit relative addressing while
BHS is a 2-byte instruction using 8-bit relative addressing. See LBRA and BHS for
details on the operation of LBHS.
LBLE 10 2F 5(6) 4
LBLE isthe same as LBRA except that it causes a branch under the same condi-
tion as does BLE. LBLE is a 4-byte instruction using 16-bit relative addressing while
BLE is a 2-byte instruction using 8-bit relative addressing. See LBRA and BLE for
LBLO 10 25 5(6) 4
LBLO is the same as LBRA except that it causes a branch under the same condi-
tion as does BLO. LBLO is a 4-byte instruction using 16-bit relative addressing while
BLO is a 2-byte instruction using 8-bit relative addressing. See LBRA and BLO for
details on the operation of LBLO.
LBLS 10 23 5(6) 4
LBLS is the same as LBRA except that it causes a branch under the same condi-
tion as does BLS. LBLS is a 4-byte instruction using 16-bit relative addressing while BLS
is a 2-byte instruction using 8-bit relative addressing. See LBRA and BLS for details on
the operation of LBLS.
LBLT 10 2D 5(6) 4
LBLT is the same as LBRA except that it causes a branch under the same condi-
tion as does BLT. LBLT is a 4-byte instruction using 16-bit relative addressing while
BLT is a 2-byte instruction using 8-bit relative addressing. See LBRA and BLT for
details on the operation of LBLT.
LBMI 10 2B 5(6) 4
LBMI the same as LBRA except that it causes a branch under the same condi-
is
tion as does BMI. LBMI is a 4-byte instruction using 16-bit relative addressing while
BMI is a 2-byte instruction using 8-bit relative addressing. See LBRA and BMI for
details on the operation of LBMI.
LBNE 10 26 5(6) 4
Descriptions of Individual 6809 Instructions 22-45
LBNE is the same as LBRA except that causes a branch under the same condi- it
tion as doesBNE. LBNE is a 4-byte instruction using 16-bit relative addressing while
BNE is a 2-byte instruction using 8-bit relative addressing. See LBRA and BNE for
details on the operation of LBNE.
LBPL 10 2A 5(6) 4
LBPL is the same as LBRA except that it causes a branch under the same condi-
tion as does BPL. LBPL is a 4-byte instruction using 16-bit relative addressing while
BPL is a 2-byte instruction using 8-bit relative addressing. See LBRA and BPL for
details on the operation of LBPL.
LBRA 16 5 3
LBRA places the specified address in the Program Counter, thus always causing a
program branch. The specified address is the sum of the current value of the Program
Counter (after the processor has fetched the LBRA instruction from memory) and the
displacement.
Data
Memory
E F H I N Z V c
ccrI
I
c
Program
Memory
mm mm 16 mmmm
DP 15 mmmm + 1
2E mmmm + 2
mmmm + 3
LBRA '+1531
22-46 6809 Assembly Language Programming
PC PC + 3 + disp
The extra factor of 3 is the result of the 3 bytes occupied by the LBRA instruction itself.
LBRA does not affect any flags or registers except the Program Counter (its previous
value is lost). Note that LBRA requires only a 1-byte operation code, while the various
conditional long branches (LBCC, LBCS, LBEQ, etc.) require 2-byte operation codes.
Thus the displacement formula for the long conditional branches is
PC PC + 4 + disp
Since the displacement is now a 16-bit twos complement number, its range has
increased to
-32768 10 (1000000000000000)£disp£ + 32767 10 (0111 1111 1111 1111 2 )
where * refers to the value of the Program Counter at the start of the instruction. Con-
sider the following section of a program:
LBRA NEXT
ANDA #$7F
NEXT CLRA
LBRN 10 21 5 4
LBRN is the same as LBRA except that, like BRN, no branch ever occurs. Thus
LBRN is essentially a no-operation; that is, control always passes to the next instruction
with no other changes ever occurring. Note that LBRN is a 4 byte no-op, since it
requires a 2-byte operation code followed by a 2-byte relative address (BRN is a 2-byte
no-op). Of course, the relative address could have any value, since it never be used.
will
LBRN is useful as a byte filler or for tuning a delay routine. Generally not a very
it is
useful instruction; it makes the set of long branches logically complete. See the descrip-
tion of NOP for a discussion of uses for no-operations.
Descriptions of Individual 6809 Instructions 22-47
LBSR 17 9 3
LBSRis the same as LBRA except that it saves the value of the Program Counter
in the same fashion as BSR. LBSR offers 16-bit relative addressing while BSR offers 8-
bit relative addressing. Note that LBSR requires a one-byte operation code as does
LBRA. See LBRA and BSR for details on the operation of LBSR.
LBVC 10 28 5(6) 4
LBVC is the same as LBRA except that it branches under the same condition as
BVC. LBVC is a 4-byte instruction using 16-bit relative addressing while BVC is a 2-byte
instruction using 8-bit relative addressing. See LBRA and BVC for details on the opera-
tion of LBVC.
LBVS 10 29 5(6) 4
LBVS is the same as LBRA except that it branches under the same condition as
BVS. LBVS is a 4-byte instruction using 16-bit relative addressing while BVS is a 2-byte
instruction using 8-bit relative addressing. See LBRA and BVS for details on the opera-
tion of LBVS.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Cod* Cycle* Bytes
LDA 86 2 2 96 4 2 B6 5 3 A6 4+ 2+
LDB C6 2 2 D6 4 2 F6 5 3 E6 4+ 2+
LDD CC 3 3 DC 5 2 FC 6 3 EC 5+ 2+
LDS 10 CE 4 4 10 DE 6 3 10 FE 7 4 10 EE 6+ 3+
LDU CE 3 3 DE 5 2 FE 6 3 EE 5+ 2+
LDX 8E 3 3 9E 5 2 BE 6 3 AE 5+ 2+
LDY 10 8E 4 4 10 9E 6 3 10 BE 7 4 10 AE 6+ 3+
22-48 6809 Assembly Language Programming
This instruction loads the contents of the selected memory byte(s) into the
specified register and There are two forms of this
sets the Condition flags accordingly.
instruction, an 8-bit form and a 16-bit form. The 8-bit form is associated with
Accumulators A and B, while the 16-bit form is associated with the 16-bit registers D,
X, Y, S, and U.
Consider an 8-bit LD using indirect indexed addressing with a double accumula-
tor (D) offset from Index Register X; Accumulator B receives the data.
E F H 1 N z V c
CCRl X X
1
rr
•c ss
X pp qq
Program
Y Memory
U
PC mm mm E6 mmmm
DP 9B mmmm + 1
mmmm + 2
LDB [D.X]
mmmm + 3
AA 16 After the processor executes the instruction LDB [D,X], Accumulator B will con-
.
tain A A, A .
Now consider the 16-bit LD of the double accumulator using indirect indexed
addressing with autoincrementing (by 2) of Index Register Y.
Descriptions of Individual 6809 Instructions 22-49
F H I N Z V C
CCR
<
XX
yy
X
Program
Y rr ss Memory
U
PC mm mm EC mmmm
DP B1 mmmm + 1
mmmm + 2
Suppose that rrss = 8E05 16 ttuu (the contents of memory locations 8E05 and 8E06) —
,
B394 16 xx (the contents of memory location B394) = 07, 6 and yy (the contents of
, ,
memory location B395) = F2, 6 After the processor has executed the instruction LDD
.
Accumulator D will contain 07F2,$), and Index Register Y will contain 8E05, 6 +2 —
8E07 16 .
Bit 1 5 resets N to
/ V is cleared always.
Note that the flags are affected according to the 16-bit value being loaded and not the
separate 8-bit values.
Form an effective address using one of the indexed addressing modes. Load that
address into a 16-bit register (Index Register X, Index Register Y, Hardware Stack
Pointer S, or User Stack Pointer U).
We will illustrate LEA using the indirect indexed mode based on a 16-bit constant
offset from the Program Counter. The result is stored in Index Register X.
22-50 6809 Assembly Language Programming
E F H I N Z V C
Program
CCR Memory
mmmm
I
B mmmm + 1
X XX yy mmmm + 2
Y mmmm + 3
U mmmm + 4
S
PC mm mm
DP mmmm + 4 + 023C
LEAX [$023C,PC]
mmmm + 4 + 023D
E5C5) = DE and yy (the contents of memory address E5C6) = 2F 16 After the pro-
16 , .
cessor executes the instruction LEAX [$023C,PC], Index Register X will contain
DE2F 16 and the Zero flag will be cleared since the result is not zero. Note that LEAX
and LEAY affect the Zero flag, while LEAU and LEAS do not; this difference is necess-
ary to maintain compatibility with the 6800 microprocessor. The 6809 assembler trans-
lates the 6800 instructions DEX and INX into LEAX instructions (LEAX -1,X and
LEAX 1,X respectively); 6800 programs often use DEX or INX for counting purposes
and employ the zero flag as an exit condition.
The LEA instruction brings to the programmer a great deal more capability
than a casual examination would suggest. It permits the easy generation of position-
independent code and simplifies the handling of local data on stacks, as well as per-
mitting the implementation of several other interesting and useful operations.
The following program segment illustrates one use of LEA. The table of values is
located 10D 16 bytes from the occurrence of the LEAX instruction. At assembly time,
the assembler computes this offset and inserts it as the two bytes following the LEAX
code. Note that the post byte for the two-byte offset case is 8D. Note also that the offset
is the distance from the updated PC following execution of LEAX.
LEA can also be used to perform arithmetic on the contents of index registers
and stack pointers. For example,
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Coda Cycles Byte* Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
LSL 08 6 2 78 7 3 68 6+ 2+
LSLA 48 2 1
LSLB 58 2 1
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
LSR 04 6 2 74 7 3 64 6+ 2+
LSRA 44 2 1
LSRB 54 2 1
The LSR instruction is identical to the ASR instruction except that LSR causes a
to be shifted into bit 7 instead of keeping it intact as does the ASR instruction. Flags are
affected the same way by both instructions except for the H flag, which is not affected by
LSR. Of course in the LSR instruction, the N flag is cleared since bit 7 is cleared. Con-
sult ASR for more details on LSR.
MUL 3D 11 1
.
Data
Memory
H I N
CCR
xx x yy
•I yy
x
Program
Y
Memory
U
PC 3D mmmm
DP mmmm + 1
mmmm + 2
MUL
mmmm + 3
If, for example, Accumulator A contains 6F l6 and Accumulator B contains 61, 6 after
,
the processor executes the MUL instruction, Accumulator A will contain 2A 16 and
Accumulator B will contain 0F 16 (that is, Accumulator D will contain 2A0F I6 ).
6F 0110 1111
61 = 0110 0001
0110 1111
1101 111
01 1011 11
0010 1010 0000 1111 - Nonzero result resets Z to 0.
I -
Bit 7 resets C to 0.
MUL MULTIPLY
ADCA #0 ROUND TO fl BITS
Descriptions of Individual 6809 Instructions 22-53
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
NEG 00 6 2 70 7 3 60 6+ 2+
NEGA 40 2 1
NEGB 50 2 1
This instruction replaces the contents of the selected accumulator or the specified
byte of memory with its twos complement. The twos complement of a number is the
when added to the original number, produces a sum of zero. The twos com-
value that,
plement of n is thus - n.
Consider twos complementing Accumulator A.
Data
Memory
CCR
XX
X
c
Program
Y Memory
U
PC mm mm 40 mmmm
DP mmmm + 1
mmmm + 2
mmmm + 3
NEGA
If, for example, Accumulator A contains 3A 16 , after the processor executes the NEGA
instruction, Accumulator A will contain C6 16 .
0V0 = 0, reset V to
* Bit 7 sets N to 1
H is undefined.
22-54 6809 Assembly Language Programming
The Carry flag (C) represents a borrow and is set to the complement of the resulting bin-
ary carry. The V flag is set if and only if the original operand was 1000 0000 The value .
2
00 16 is replaced by itself, and only in this case is C cleared.
we defined the twos complement as the ordinary (ones)
In the illustration above,
complement The sum of any number and its ones complement must have ones
plus 1.
in every bit position, since any position that is in the original number will be 1 in the
ones complement and vice versa. Adding 1 to the number with ones in every bit position
gives a sum of zero (with a carry, which is ignored), so adding 1 to the ones complement
must give the twos complement.
NOP — No Operation
Object No. of No. of
Coda Cycles Bytes
NOP 12 2 1
NOP is a one-byte instruction that does nothing except increment the program
counter.
Typical uses of NOP are the following:
NOP is seldom used in completed programs, but it is often quite handy in the debug-
ging and testing stages.
OR — Logical (Inclusive) OR
ORA
ORB
ORCC
Immediate Direct Extended Indexed/Indirect
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Coda Cycles Bytes Code Cycles Bytes Code Cycles Bytes Coda Cycles Bytes
ORA 8A 2 2 9A 4 2 BA 5 3 AA 4+ 2+
ORB CA 2 2 DA 4 2 FA 5 3 EA 4+ 2
ORCC 1A 3 2
- .
This instruction logically (inclusive) ORs the contents of a memory location with
the contents of Accumulator A or B or the Condition Code Register. Only immediate
addressing can be used with CCR.
First consider the accumulator OR using immediate addressing and Accumulator
A.
Descriptions of Individual 6809 Instructions 22-66
Data
Memory
CCR
XX
of
>B
X
Program
Y Memory
PC mm mm 8A mmmm
DP AB mmmm + 1
OR A #$AB mmmm + 2
Suppose that xx -
E3 16 After the processor has executed the instruction
.
ORA #$AB,
Accumulator A will contain EB 16 .
E3 1110 0011
AB 1010 1011
1110 101 1- -*- Nonzero result resets Z to
— Bit 7 sets N to 1
V is always cleared
E F H 1 N z V c
CCR [x X X X X X X x r
•<:
mm mm mmmm
DP mmmm + 1
This instruction logically ORs the contents of the following byte of program memory
with the contents of the Condition Code Register. This has the effect of setting all the
flags that are logically ORed with Ts and leaving unchanged all the flags that are
logically ORed with '0's. The following patterns will set individual flags:
Of course,setting more than one bit position will set more than one flag at a time.
However, only a few of the possible operations are really useful. In particular, we should
note:
ORCC #%01000000 DISABLE FAST INTERRUPTS
ORCC ft%00010000 DISABLE REGULAR INTERRUPTS
ORCC H00000010 SET OVERFLOW
ORCC nOOOOOOOl SET CARRY
Remember that setting an interrupt mask disables the interrupt from that source.
PSHS 34 5+ 2+
PSHU 36 5+ 2+
The PSH instruction will push onto either stack any or all registers except the
Stack Pointer being used. Consider pushing both index registers onto the Hardware
Stack.
Data
Memory
E F H I N Z V c
CCR PP ssss - 4
J I
qq ssss - 3
tt ssss - 2
uu ssss - 1
D
<: ssss
X PP qq
Program
Y tt uu Memory
U
S ss ss
PC mm mm 34 mmmm
DP 30 mmmm + 1
The second byte of the instruction specifies the registers to be saved as follows:
7 6 5 4 3 2 1 ^- Bit No.
Each bit position that contains 1 causes the corresponding register to be saved on the
stack. If thv register is 16 bits in length, the process^/ saves its contents as follows:
1. Decrement the Stack Pointer and store the low-order byte of the register at
the address in the Stack Pointer.
2. Decrement the stack pointer again and store the high-order byte of the
register at the address in the Stack Pointer.
If the register is 8 bits long, the processor performs only one storage operation and
decrements the stack pointer only once.
The order is as follows (with the lowest memory address at the top):
Note that some (or even all) of the registers can be omitted. The processor decre-
ments the Stack Pointer once for each byte that it saves. The internal hardware deter-
mines the order in which registers are stacked; the order in which the programmer
specifies registers does not matter. For example, the instructions PSHS A,B,X,DP and
PSHS DP,A,B,X are identical. You may specify the double accumulator D instead of A
and B.
Note that the Hardware Stack Pointer (S) cannot be pushed onto the Hardware
Stack, nor can the User Stack Pointer (U) be pushed onto the User Stack. Thus the stack
in use determines the meaning of bit 6 of the post byte. Setting bit 6 for PSHS will cause
the User Stack Pointer to be pushed onto the Hardware Stack, while setting bit 6 for
PSHU will cause the Hardware Stack Pointer to be pushed onto the User Stack.
PULS 35 5+ 2+
PULU 37 5+ 2+
The PUL instruction will pull from either stack any or all registers except the
designated Stack Pointer. Consider pulling the Condition Code Register (CCR), Index
Register Y, and the Direct Page Register (DP) from the user stack.
H I N V C
CCR
X
<
Y tt uu
U ss ss
C mm mm
DP
PULU CCR.Y.DP
The second byte of the instruction specifies the registers to be loaded exactly as for
PSH. The order in which registers are pulled from the stack is the opposite of that in
which they are pushed. As with PSH, you can omit any or all of the registers, you cannot
Descriptions of Individual 6809 Instructions 22-59
pull a stack pointer from its own stack, and the order in which registers are specified in
the assembly language instruction has no effect on the order in which they are pulled
from the stack.
Note that, unless you are loading the Condition Code Register itself, loading
registers in this way does not affect the flags. If you wish to load a register from a stack
and affect the flags, you should use the LD instruction in the autoincrement mode with
the appropriate Stack Pointer. For example, to load Index Register Y from the user stack
and set flags accordingly, use the instruction LDY ,U+ +.
The instruction PULU PC loads the Program Counter from the user stack and
thus serves as a Return from Subroutine instruction in which the linkage is in the
user stack, rather than the Hardware Stack. Pulling any set of registers that
includes the Program Counter has a similar effect. The programmer can transfer con-
trol to and from subroutines through the user stack; a sequence like
PSHU PC
JMP SUBR
transfers control to subroutine SUBR after saving the Program Counter in the user
stack. Note, however, that the subroutine will have to increment the return address past
the JMP instruction.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ROL 09 6 2 79 7 3 69 6+ 2+
ROLA 49 2 1
ROLB 59 2 1
This instruction rotates the specified accumulator or the selected byte of memory
one bit to the left through the Carry flag.
Consider rotating a memory byte using indexed addressing with zero offset from
Index Register Y.
22-60 6809 Assembly Language Programming
E F H I N z v C
CCR
ppqq
"{'.
X
Program
Y pp qq Memory
U
PC mm mm 69 mmmm
dp] A4 mmmm + 1
mmmm + 2
mmmm + 3
ROL ,Y
are2E 16 and the Carry flag contains 0. After the processor executes the instruction ROL
,
,Y memory location 1403 will contain 5C 16 and the Carry flag will contain 0.
Location 1403
•»0 V = 0, reset V to
Bit 7 resets N to
The overflow flag (V) is loaded with the Exclusive-OR of bits 7 and 6 of the original
operand; these bit values are the same as those of the resulting Carry (C) and Sign (N)
flags.
The ROL instruction can be used to include the Carry in multiple-byte shifts
and to move serial (1-bit) data to or from the Carry flag.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
ROR 06 6 2 76 7 3 66 6+ 2+
RORA 46 2 1
RORB 56 2 1
Descriptions of Individual 6809 Instructions 22-61
This instruction same as ROL except that the rotation is from left to right.
is the
The flags are affected in the same way except that C is now loaded with bit and V is
unaffected. Consult the description of ROL for more details.
RTI 3B 6/15 1
This instruction restores the state of an interrupted task by loading the Condition
Code Register and Program Counter from the hardware stack. If the Entire flag (E) is
set, the instruction loads all the other user registers from the hardware stack.
H I N
ccrI 1
XX
•{: vv
X pp qq
Y tt uu
U w WW
S ss ss
PC ii kk
DP dd
RTI
.
After the processor executes the RTI instruction, the registers will appear as follows:
First, the condition code is pulled from the stack, and the contents of bit 7 (E) are
examined by the hardware of the CPU to determine whether the entire machine status
has been stacked, or just the subset CCR and PC. The order of the registers in the stack
is the same as in the instructions PSHS and PULS. Note that, as in those instructions,
RTS 39 5 1
Program control is returned from the subroutine to the calling program by pulling
the return address from the stack and placing it in the Program Counter.
E F H I N Z V c
CCR
| I
•{:
x
S ss ss
PC mm mm
DP
RTS
Descriptions of Individual 6809 Instructions 22-63
The previous contents of the program counter are lost. The processor increments the
Hardware Stack Pointer after loading each byte, so the final value of that pointer is two
larger than its starting value.
Each subroutine normally contains at least one RTS instruction; this is the
last instruction executed within the subroutine and causes control to return to the
calling program. RTS does not affect any flags. Note, however, that no RTS instruc-
tion is necessary if the last instruction in the subroutine restores a set of registers
including the program counter from the hardware stack. For example, the instruction
PULS A,B,CC,PC will restore Accumulators A and B and the Condition Code Register
from the hardware stack before returning control to the main program. Of course, the
subroutine must include an appropriate PSHS instruction, such as PSHS A,B,CC.
This instruction subtracts Accumulator B from Accumulator A and sets the condition
flags accordingly. The 6809 assembler handles this instruction to allow source com-
patibility with the 6800 processor.
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycle* Byte* Code Cycles Bytes Code Cycle* Byte* Code Cycle* Bytes
SBCA 82 2 2 92 4 2 B2 5 3 A2 4+ 2+
SBCB C2 2 2 D2 4 2 F2 5 3 E2 4+ 2+
This instruction subtracts the contents of the selected byte of memory and the
contents of the carry flag from the contents of the specified accumulator.
Consider SBCB using an 8-bit constant offset from Index Register Y.
1
E F H 1 N z V c
ccr| X X X X "1
ppqq + 3E
<:
X
Y pp qq
U
S
PC mm mm i mrnn
DP
SBCB $3E,Y
1. After the processor executes the instruction SBCB $3E,Y the contents of Accumula-
tor B will be DF,,.
14 = 0001 0100
Twos complement of 1 = 1111 1111
0001 001
Twos complement of 34 = 1 1 00 1 1 00
1101 1111- Nonzero result resets Z to
I
1
V = 0, reset V to
Bit 7 sets N to 1
H is undefined
Note that C is the complement of the resulting carry since it represents a borrow.
The most common use of SBC is in implementing multiple-precision
arithmetic; this instruction allows borrows from previous byte-length operations to
be included in the current byte-length operation.
interrupt — that is, the 6809 will not respond to the fast interrupt request control line.
No other registers or flags are affected.
Condition Code Register (the regular interrupt mask bit) . This instruction disables the
6809's regular interrupt — that is, the 6809 will not respond to the interrupt request
control line. No other registers or flags are affected.
SEX ID 2 1
Data
Memory
I N
CCR
k^T \
B bxxx xxxx
X
Program
Y Memory
U
PC mm mm 1D mmmm
DP mmmm + 1
mmmm + 2
mmmm + 3
SEX
STX Object No. of No. of Object No. of No. of Object No. of No. of
STY Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
STA 97 4 2 B7 5 3 A7 4+ 2+
STB D7 4 2 F7 5 3 E7 4+ 2+
STD DD 5 2 FD 6 3 ED 5+ 2+
STS 10 DF 6 3 10 FF 7 4 10 EF 6+ 3+
STU DF 5 2 FF 6 3 EF 5+ 2+
STX 9F 5 2 BF 6 3 AF 6+ 2+
STY 10 9F 6 3 10 BF 7 4 10 AF 6+ 3+
Store the contents of the specified register at the selected memory address. There
are two forms of this instruction, an 8-bit form and a 16-bit form. The 8-bit form is as-
sociated with Accumulators A and B, while the 16-bit form is associated with the 16-bit
registers D, X, Y, S and U.
Consider the 8-bit case, storing Accumulator B using the indexed addressing
mode with a constant 16-bit offset from Index Register Y.
Descriptions of Individual 6809 Instructions 22-67
H I N
CCR
ppqq + 0302
•<: XX
Y pp qq
C mm mm
DP
STB $0302,Y
Suppose that xx = 63 16 and ppqq = 0238 16 After the processor executes the
.
Bit 7 resets N to
J V is cleared always.
Now consider the 16-bit case, storing the D register using indexed addressing,
autoincrementing Index Register Y by 2.
CCR
XX
°{: yy
X
Y pp qq
U
S
PC mm mm
DP
STD ,Y+ +
22-68 6809 Assembly Language Programming
executed the instruction STD ,Y+ + memory location 1430 will contain Cl 16 , memory
location 1431 will contain 9A 16 and Index Register Y will contain 1432 16
, .
-+ Bit 1 5 sets N to 1
V is always cleared
Note that the STS and STY instructions have a two byte object code, the first byte
being 10 16 .
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
SUBA 80 2 2 90 4 2 BO 5 3 AO 4+ 2+
SUBB CO 2 2 DO 4 2 FO 5 3 EO 4+ 2+
SUBD 83 4 3 93 6 2 B3 7 3 A3 6+ 2+
Subtract the contents of the selected byte ofmemory from the contents of the
specified accumulator. There are two forms of this instruction, a one-byte form and a
two-byte form. The one-byte form uses an 8-bit accumulator (A or B), while the two-
byte form uses the 16-bit Accumulator D.
First consider 8-bit subtraction using Accumulator B and base page direct address-
ing.
CR X X X X *
J (b
A
XX
PC mm mm
DP dd
S UBB $3 1
1
6B31) » A0 16 After the processor executes the instruction SUBB $31, the contents of
.
Accumulator B will be 43 16 .
E3 1110 0011
Twos complement of AO = 0110 0000
0100 0011- Nonzero result resets Z to
IV 1 0. reset V to
--Bit 7 resets N to
H is undefined
The SUBA and SUBB instructions are used to perform single-byte subtractions
or to perform the subtraction of the low-order bytes in multibyte operations.
Now consider the 16-bit form SUBD. We will illustrate its execution using
extended direct addressing.
H I
CCR
XX
°<: yy
PC mm mm
DP
SUBD $A074
the processor executes the instruction SUBD $A074, the contents of Accumulator D
will be F303 16 — that is, Accumulator A will contain F3 16 and Accumulator B will con-
tain 03 16 .
1
*OV0 = 0, reset V to
- Borrow sets C to 1
Note that the Half-carry flag (H) is not affected by SUBD and that C is the com-
plement of the resulting carry, since it represents a borrow.
22-70 6809 Assembly Language Programming
SWI 3F 19 1
SWI2 10 3F 20 2
SWI3 11 3F 20 2
This instruction increments the program counter, sets the E flag (bit 7 of CCR) —
indicating that the entire state of the processor has been saved, and stores all the user
registers except the Hardware Stack Pointer in the hardware Stack. Control is then
passed through a vector table at the high end of memory.
Data
Memory
CCR I 1
XX
<: yy
X pp qq
Y tt uu
U vv WW
S ss ss
PC mm mm mmmm
DP dd mmmm + 1
SWI
Descriptions of Individual 6809 Instructions 22-71
Note that control is passed to a service routine by placing into the program
counter the address located at FFFA and FFFB, and that the interrupt and fast interrupt
mask bits (bits 4 and 6 of the CCR) are set, disabling the maskable interrupts.
The processor stores the user registers in the same order as the PSHS instruction.
The final contents of the Hardware Stack Pointer are the original contents minus 12
(C 16 ). The E flag is set to 1 so that an RTI instruction will restore the original state,
except that the Program Counter have been incremented by 1. Thus an RTI will
will
SYNC 13 2 1
This instruction simply halts CPU execution until a peripheral device requests
an interrupt. Any interrupt clears the halt. If the interrupt is enabled and lasts 3 cycles
or more, the processor will respond to it, stacking the registers and transferring control
to the appropriate vector address. If the interrupt is masked (disabled) or is shorter than
3 cycles long, the processor simply continues to the next instruction without stacking
registers or transferring control to a service routine. SYNC differs from CWAI as
follows:
1. SYNC does not provide a means for enabling interrupts during instruction
execution.
2. The processor tristates its busses while executing SYNC, but not while
executing CWAI.
3. SYNC provides a continuation exit without an interrupt response, whereas
CWAI requires an interrupt response.
Begin execution of
SYNC
the SYNC instruction
^^Masked ^^^No
1
Continue Stack machine
execution at the Status transfer to
next instruction applicable interrupt
in sequence Service Routine
TFR 1F 7 2
This instruction transfers the contents of Accumulator A to Accumulator B and sets the
flags accordingly. The instruction is handled by the 6809 assembler to allow source com-
patibility with the 6800 processor.
Descriptions of Individual 6809 Instructions 22-73
Data
Memory
E F H 1 N Z V c
ccr|
1
XX
r. :>
X
Program
Y Memory
U
S
PC mm mm 1F mmmm
DP 89 mmmm + 1
mmmm + 2
TFR A,B mmmm + 3
end of the execution of TFR A,B both accumulators will contain the number 6A 16 .
Note that TFR destroys the old contents of the destination register. You can save
those contents in the source register by using EXG instead. TFR, however, does not
change the contents of the source register.
All TFR instructions require two bytes of program memory — the operation code
and the post byte (the immediate data), which specifies the source and destination
registers. Be careful of the fact that some TFR instructions are meaningless (undefined
register codes), while others are illegal (transferring contents between registers of
different sizes).
The post byte for the TFR instruction is identical to the post byte illustrated in the
EXG instruction description. The TFR post byte's higher order four bits define the
source register while the lower order four bits define the destination register. The flags
are unaffected unless CCR is the destination register.
22-74 6809 Assembly Language Programming
Object No. of No. of Object No. of No. of Object No. of No. of Object No. of No. of
Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes Code Cycles Bytes
TST OD 6 2 7D 7 3 6D 6+ 2+
TSTA 4D 2 1
TSTB 5D 2 1
This instruction sets the Sign and Zero flags according to the contents of the
specified accumulator or the selected byte of memory.
Consider testing a byte of memory addressed by Index Register Y with Accumula-
tor A offset.
CCR
ppqq + rr
tion TST A,Y the sign and overflow flags will contain zero and the zero flag will contain
one. No registers or memory locations will be changed.
Descriptions of Individual 6809 Instructions 22-75
Bit 7 resets N to J
0^
V is always cleared
The TST instruction lets the programmer set the flags according to the contents
The 6809 assembler translates this 6800 instruction into the 6809 instruction
CWAI #$FF. This instruction is handled to allow source compatibility with the 6800
processor.
Appendices
The following section presents a complete set of reference tables for the 6809
instruction set.
Appendix A summarizes 6809 instruction operations and effects, and is organized
by function to display the capabilities of the 6809 processor. Appendix B summarizes the
indexed and indirect addressing modes: which modes are available, their assembly
language forms, and the resulting object code post bytes. For each instruction
mnemonic Appendix C shows the available addressing modes, its object code, execu-
tion time in machine cycles, and the number of bytes occupied by the instruction.
Appendices B and C can serve as aids to hand assembly of 6809 instructions. Appendix
D lists all the valid object codes and their instruction mnemonics, and Appendix E lists
all the indexed and indirect addressing post bytes and the assembler forms which gener-
ate them. These two tables can be used for hand checking and disassembly of object
code, tasks sometimes required in the debugging of an assembly language program.
A
Summary of the 6809
Instruction Set
The registers
A. B Accumulators
D Double Accumulator (A and B concatenated, A high-order)
DP Direct Page Register
X, Y Index registers
PC Program Counter
S Hardware Stack Pointer
U User Stack Pointer
CC Status (Condition Code) Register
The flags (statuses), starting with bit of the condition code register and proceeding to bit 7:
£
o
E
«
CO E
*S •
a* •oS £
fe
• a o (0 -— o>
o CO£
E"° E
!•
E
« •
E £
4> o a
S " o E
c .S IA
=f
!fc in
O .«
lis co a
2 o
°t
DO 'a> o
IS
*-
.3
$ ~ CO
O • . o > -2 £
511 3 x:
$ o |i
~
i» „ o o
W a)
Sac a * «: <
I• ^s
8.
0>
o
g
•
*
.fc
-c
"H
53
E
: o c
o ^
Hi
5^5
I
—- c
E +
C C w
!•§*
co 15
I&
sis
8
1 if
00 -o
1
— toI ©g
~i 1 .18
_J CO <
lip sPz 5 o
H; CO co
£
f E J O 2
+ + + +
io<oifl co r» <o mcoifl cor^co
e
•
a
a + + + +
< cxcotN «^-ro CM CO CM co^co
oo® * oo® E __
CO* ^ oo® E 00 « 00 « oo £ oo »
»§"" S "^ £
a *;
^ «"S^
«"S^ ^ ^ »"8* <0 t3
2 S • CO —; • co
5 '•» 5
& a l. «o >• • .£ o o£
,§5.2
•
II <^£ CB
X. =>"f 1
o E
3
5 •>
co
2Z£
« o w
. • T
JO'S *
MiAv
5 **
w <> o S
ifl . ?"
• 2 c 5 s 5 J? *
5S< < ^ o « £
Ill
£
C CO
.a ? .
J= .2
2 m'
o «** 118
Is? £•€ x
o c g E •
.
S eg &8 £
I ll i .2 •
If if?
o " .E es~ J ~ E |
S o £"
s
-1 CO co CD S-2 J?
5 2*£
=5 (0 o -* S I £
Ml +
— a
CO
C
=? > -E.T.
5
— at s
«; 2 -6
—
CO **
c >
• c
i«
° s
n
SCO £ •
to ?•£.
-C
Mi£ + n
~^ <D TJ
CO o
> — s si —
; — •
s • £ •
** x
c
o • s * a® i|
*-
U 00
lis «f — Q. £
S ** co
•= m
£ >
I i
o —x ot oO
. I CO .C
V • o • „< o * o o< < oo< O
I
S% 9 WOO-8.E
< o 9
H tt» "O
ON
o
oo
SO 9
CD (0
+ + + + +
* tf> * co r* <o * in * * in >* >* m *•+ r» oo r»
+
f» 00 f^
+
<
X
+ + + + + +
e CM CO CM CM CO CM CM CO CM CM CO CM CM CO <N CM CO CM CO ^- CO
+
CO * CO+
•
a
a
<
CO®!
™^o
g-3*:
00*°^
t:^o
"g-o-.
V
oo*
^-o^
^
o oo"t
w co-d
»"t »"£
»"o
«oJ=S
"bc
oo<°§
w 7" O
"g-o*:
™
c c
""b
c
CO "O
<§£
« P w .
§ 3*8
|I|
u
?(S ° "P 13
3J "
s
8
III
3
o
"O
X «»
-.
• X
*•
§ II
I E-2
I i s
2.£»
cT. E
C E £.2
s fc 3 E
Sod O
O
BO
" E
| 3 „_
*S
i.
i
•
§ 2?? = + §§>!
S2?
^
• o
(0 §
Til
^i i "x 5 o»
- s ~
<a
~ _ oo
I
* I* s< 1
-So
1 £ 5 i =1
—X -o3 o
SSeJ ff
!*$
"* C?t:
oj 5
X 3
0(0
„_
O CO
U
<
i
O i
+
co p» co * in *+ *• u> *+ * » ^+
X
C NCON+ CM CO CM
+
CM CO CM
+
CMCOCM
+
CMCOCM
+
CMCOCM
+
a
a
<
< 03
< < 03 < CO O
DC CC 03 O O CO 00 03
OO CC DC
OO 03 03
CO (0
2>
CO (0
3 D
CO
u
IM ri
is •
o O
a o o5
« t-s
§ « $
_i
~CJ o
(0 Oat
< »I ?
2 S 1 B
•
E C CPU
CO
</>
£• 181
1 '
S" i » co
c
r*
*
£ cb
r^ 4=
CO
?^ i
f is
8B£±!
i f ?!
+
oms+ +
to r» co co r*» co
+
co r^ to co r^ co
+
co r^ co
+
<
X
+ + + + +
e CM CO CM CN CO CM CM CO CM CM CO CM CM CO CM
» co o)
g o
? o
0) •
O
o o
.2 w
is
S o
< o
ii
O a <
o
I!3
,_
•
E
o "t
w o oo
I
8
3 «
E x
E o
ca
iS < 13
.2
3- (O 2 «D
o *-
+ • + •
<S ® "x a 8*2*
00
CD
c
C J- Tt -2
< E 3 E
5®< •>!
o
o -3» tj
w CO i-i I-i > o
,
"*>
CO
£
* —
tj o i
a
x -6 ss
o < o < ilff
o o M- x -o O *
0.3 —
1
Q
-I o
< Q
< S <
<
X
"5
c
•
a
a
<
c «
2- § 00 ** 00 oo oo jr
< 00 < 00 Q
OO QQ O
QQ QQ Q
<< << <
< < E
3
C0
-O
J s CO E 3
U J3
U 3 CO
U 3
e
o
U
< O
o tl t 1 < oO
«5 1 1 E E
E E
CO E E E S E E • s o o
o o *-
& .5 .« 2 it «o 00 >
>
00 £
o
«J
• s£ ™ O ^ CO
O S m »
° I co cp
CO
CO CP
si o«9cb CO co C
S.S CO CO
< o ** « S S T) » „ s
I S 1 i 3 I £ . 1 %
a
T< J?
O O 3?co •k-§
*£ •
0J 00 €
1 3 2 — .Q3
1
it
U -J 7?*
7>% X
U _J O
3 w
o
X 3 I ^
U CO ~-C0
<,
Jj
< < Q £« « < < <
(0
< o
o X X X X X X X
> o O X X X X o o X X X
N X X X X X X X X X X X
10
3 z X X X X X X X X X X X
*•
5
CO
X X X X
u.
Ill
w
•
o CM CM CM IO IA « CM CM CM CM ^,
>
O
<
x »
'"5
£ CM CM CM * «• CO CM CM CM CM eo
c CO
•
a
<
10
o 00 00 00 CO 03 CO 00 00 00 00 CO
a o o o o a o o o o o o
O
o ,—*—k
< CO < 00 < 00 a (03>-X < 00 < 00 a
Q O h- t-
oo <ss o o
ol a. a.
a. 00 00 oo 00
E zz 22
U 2
o 2 22 > CO 00 3D 3
e << mm CJ uuu o UJ UJ CO (A CO CO 00
2
oo 2 O _
s
* * to*- £ 01 *—
O S X -n
i,i.J
co co
sill
5= y
3"*
E
E
s +
CO «* CO
<
K
e
&
2
«si2 <2- g
o «-
II II
II 10 « X X H
0»-«->ZNOZ*~N >,~ 00
II
o
eg
E
E
3
CO
< CO CO CO CO CO'CO cocococococococo
1
<
NNNNNNNMNNNNNN
J
UlOOU)--V)uiO(OI-S l >'J
* »
M
.2 £
1u
* 3
g5« g .2«
?!
« o Is
8b
£ eo <o
*. g n
— Q
a!
«o .
+ +
"8
3
si o>o > -- ill* • 1
C > II > II
Ifc £5
£
O «-
0«-«->zn02;«-n^ ,- 000«-
c «{ t 5.1
o i >>> > >> is?
i
>> —
II
o 5. „
II
o oz o U
II II
OUNZNOONOCJZZNZ>>
II II II II II II II II
'is
o
ST
ea
E
E
s
(0(0<0(O(D(O(0(D(D<0<D(O<O(OC0CO
< lAIAIfllOlfllAiOlOlAIOIAlAIOIAlOin
<
X
'5
^•^•Tj-^-^-^-TtTrTj-TtTtTt^-TtTj-^t
e
I
(O<0<O<0<O<O<0(O<0(O(0(0(0<0.<OCO
aaaaaaaaaaaaaaaa
« g « « « m g « « « « « ,S ,S ,S .!
:
5 S 5 5 6 5 o 5 5'5 o 5'0'0'0"0
: : : : : : : : - ! i
uuHjUOIIjjj j5zO>
QQflQCOOQflQflQflQflOGOflOCQflQOQCQOuflQ
CO (B
[ O A CD
<
-, E
X 3
o E
3
< Ml
-i
& < *
83 *
CJ O OO
E
E
3
S/5
<
X
e
i
a
<
53 < m
DC E
< CD < CO
22 < < CO
CO (0 OO < u o
Ui UJ
<< O O CJ o o QQ
tUctiedO
0»BJCKlO J»»«|B«u
A- 13 6809 Assembly Language Programming
. «> .2
6 3
*1S
(A ill
03
O
<
S
8?
5= s i
3
S°
£»
rx i
si 3<3 °
« "S « £
s a
IS g o to
° «
C (D 00
*
<l
o-o x o
o • «o
*x
(J-2
.s>
O «
X .2 < 03 < 03
j» «
< I
£ 2 £
c °
o»
o w
* *^ (A
*""
^_ S2 «= £ 2*
+ "~ 3 £§££
•
I > o»
T -5 r*
0)
s *f<S J
c S So
! 8"iei|
c « 1 § OO |
o -x £ * -xJ««£O
u oJS S> o {?
-I UhWO)
<
E
E
3
<
<
K5
c
•
a
a
<
OO _l
03
_l
03
DC OC O O
LU UJ
oc cc
OO
CO to (A (A
zz oc oc
that
follows: pushed.
specified
negative address perform
instruc-
indexed/
load
as
or LEA
to byte
[S(LO)l
the the
[S(HI)1
and stack
effective
zero
of U).
onto each
B) or
employed
or or
any
for an
S, specified
Stack.
for
B to Appendix
Y, be [PC(L0)1
IPC(HI)]
[U(L0)l
[U(HD]
[Y(LO)l [Y(HI)l [X(LO)l
[DP] [CC]
registers
E or
(X, calculate
[B] [A] cycle
in - - —
1,[[SP]]*-[X(HI)]
— — — —
that
also - — — -
1• A according
of
(see
to one
a. register
to registers [[SPH [[SPH [[SPH [[SPH [[SPl] [[SPH [[SPH [[SPH [[SPH
o subset pointer by
*5
a
Accumulator
modes
but 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
address
intended
1 specified
store
- - - - - - - - - - -
O use,
the - — — — — — - —
effective
addressing
primarily
repeated
- — «-
[SPl^lSPl
time
none,
arithmetic.
byte
16 contents
into [SPl [SPl [SPl
except
1; 1; 1; 1; 1;
EA
1;
the post all,
are for
6-bit
1; 1; Execution
— Condition:
address
indirect
= » = = = - - Push Stack,
[ACx]-00
Test value.
[regl
Form tions once
1 Test
b7 b6 b5 b4 b3 b2 b1 bO
u
> o
N X X
3 z X
CO -
X
u.
UJ
• + + +
o cm <* *r
>
O
+ +
«- CM
i
CD
CM CM
3
o
e forms forms .2
(B
i S
o ind. ind.
J )) ))
'E
o 3
CO
E XX
•
TSTA) TSTB LEAX LEAY LEAS LEAU
CO CO
e 0. 0.
2
as
bits
specified
pulled.
stack
1 register
1 + byte
+ the
specified
[SP]
Status
each
[SP]
1 1+
from
1111 -
1 + + + +
—
o• 1 + for
+ 1 1 +
Stack.
from [SP] Stack.
£ + + [SP]
[SP] [SP] [SP] [SP]
[SP] registers
cycle
o [SP]
t• [SP]
[SP] [SP]
[SP]
—
-
«-
-
[[SP]],
—
«-
that
from
a.
registers
—
of one
— [[SP]],
to
e — — [SPl [SP] [SP] - [SP]
[SP]
o [SP]
—
pulled
by
[SP] [SP] subset
« load
[SP] [SP]
[[SPl],
Pointer
[[SPl],
£ [[SPH,
[[SP]],
[S(LO)l
byte
o and [[SP]],
[[SPU,
[[SP]], [[SP]],
[S(HD]
«-
any the
increases
«-
[[SP]], [[SP]], - - or by
— — or or
for
byte «- —
— «- time
[PC(LO)l
[X(LO)l [U(LO)l
[PC(HI)]
[LMHIH none,
[X(HD] [Y(HD] IY0.OH
except
[CC] [DP] determined
Condition:
1; 1; 1; 1; 1; 1; 1; 1; all,
Execution
Test
follows:
= = « = = = = = Pull stack,
are
bO b1 b2 b3 b4 b5 b6 b7
u
>
N
(0
3 z
s -
(0
X
Ik
111
• +
>
< O
x M
•
c > CM
CD
a.
a
<
3
o
e .2
(D
d>
o
a £
O
o
"E
o CO
_i _i
3
E
• =>
a. a.
3
e
2
•
a
>>
(DWIUpUOO) )|3BIS
l-
Summary of the 6809 Instruction Set A- 16
inter- flag.
terrupt saved,
corres-
n E
• o - 2 8
te <- *. <p o
O e> *; »>
^j
'I'll
$ > O «5 75
O s "
3 9 * c •
•
.so
!
r • CO S. « • o c
a.
2 = := — := — =: — 5 5 s « 8
§ 6
^ £ 2x2?2f- -|e £c"
2.
2 L(L33>->-XXQB<u|^.a)«£
i
o * ill liiliM ii •=!*!•?
« (AVKAIAOKOOXOdllAIAUSc^Sn^
^< 5» C = S "- C
iiiiiiiiiiii=s-«»s
7* cococotoco</>co(/)tocococow>c s H:
i7 1 1 1 1 1 1 1 1 1 1 1 I 5 1 1 g 5£
O.UjCO<OCOCOtQt/)CO<0OTtQtO»
O
>
N
oo £3
z
3
CO
X
u.
E
in
E
3
(0
•
< O
> CM
< u
X
'5 •
•
e * CM
CO
i
<
»
e 00
10
ID
& O
O
o
e
o <
E
•
e
2
i )dlMJ0lll|
H
;
<0 s S
- Is
e Is
i S
+
- z, - 4. + + + i
+ s 8iq=o=o=
7Z W CO a
"5-2 + +
. . J2
~ + + g§S§ffiS2 7e ffi
| g _ CN CO
5 ? f w i to„ I
77i TT
J
f i ijii
1 1 1
CO CO
JL
i_ A
i i i i i i i i
c fTITlTii 52 g "g WW CO JO W WW CO
o J E» CD
i"o « is
oo5o
it ga££ y 1 7777777
QXX>->-DDD. o
a. tu CO cS's
o<
E
E
3
C/5
<
<
3S3
CO CO CO
(p»nu|»uo3) )diujcnu|
Summary of the 6809 Instruction Set A-18
if
if
il
CD
ijz
!n
CO
f*
CO ~ 'J
CO
"It
CO
|e «l
o «
6 § a 2
to S
5 o 1?
—
cl „ — s "
Q 00 < O „ 3g > ec
OS
c to
*8 « .E o ."
wwww * 5 • .2 § 10 o P
.a a <3^* si* *
---- Il5 II Jlf
li is
w—
— w *—
w— w — *» 3 * §17.81?
S5
I c I* B ft
|
1 .2
-S ** 1
lijl
„„„_o
I I i
z *
wco wto a.
<
X
'5
e
•
a
a
<
z oc et
DC O 2
D J Z
to
Non-indirect • Indirect • n
"5 • o •
Type Form Assembler > Assembler
>>
Post-Byte a Post- Byte U to
Form Op-code + + Form Op-code + +
No Offset ,R 1RR00100 LR] 1RR10100 3
Constant Offset 5-Bit Offset n.R ORRnnnnn 1 Defaults to 8-bit
from R 8-Bit Offset nn,R 1RR01000 1 1 [nn,R] 1RR11000 4 1
Constant Offset 8-Bit Offset label. PCR 1XX01100 1 1 [label. PCR] 1XX11100 4 1
Extended - - - -
1 6-Bit Address [mmnn] 10011111 5 2
Indirect
R = X. Y, U, orS RR:00 = X 10 = U
XX = Don't Care 01 = Y 1 1 = S
Note: This chart conforms to Motorola nomenclature; their use of square brackets [ ] indicates to the assembler that
the addressing mode is indirect —
thus, their use of [ ] differs from the use in Appendix A.
c
6809 Instruction Codes, Memory
Requirements, and Execution Times
• CM CM CM CM CM CM CM CMCMCMCMCMCMCMCMCMCMCMCM
E 6 >
• 2 CO
0) o
> (9
o •
a
CO co co co co co co co cococococococococor^coco
•
ec
zo
o
• 4u)MJuiN4
CM CM CM CM CM CM CM
u.iononiio<0<-0ooai
CMCMCMCMCMCMCMCMCMCOCMCM
3 §5
•
co
X
6 >
z to
+ + + + + + ++
CMCMCMCMCMCMCMCMCM
+ ++
CM CM
++
CM
+ +
CM CM CO
• <
a
o a>
+ + + + + + +++ ++ ++ + +
X
• • u • co
oc • 09 "O <
CO
5o>5coco**-ooi-» 510 •- °
§5 <ui<ujuj<uj <D os ^ iu
it
<o U
<. w *-
° COCOCOCOCOCOCOCO coco^
6
1> CO coco CO
z eo
a•c (0
o •
• 6 muotnuDr^mmt-* r* mm r* uouooo
X zo
IU
CO
• 13 00
§8 oioioon"*^ to ^ >i»in u. «- ^
cou.cou.u.oQu.r^>f*» oqu_ r^ co u- «—
Z CD
»- M
to o •
• 6
a
*t^**<0**t<D<D "* <* <o ** ^- r»
5 zo
u a>
CO
3* O)O)G0QDC0^^0Ot*»
0)00)000)00 IOIO
O) O
u.
O
«- »-
O) O
O
t-
ID
CMCMCMCMCOCMCMCM CM CM CMCM^-
6 >•
• a Z CO
eg «•- to
'5 o o •
• CMCMCMCM^CMCMCO CMCM CM CM U)
s
E
ce
Z CJ
£ <s
CO
• OS
3 -a
OJtDCDOQCOrt'tU lOUS «- «- O
cf<S aunouDUr- 00 00 •-
6
Z
>
co
^ -^
«•- (A
• o •
CO CM CM CM CM CM CM
Z CJ
< 00 co r^ r* u. u.
< m
co * >n ** \r>
4
(0
to e
S88S§ozzz J ^i» is ow SSc5l8i?fc!y
tt
3 ,
"iS"l
i5
zei:
^>°c ^5SSS
• •
2 E
o£
C-2 6809 Instruction Codes, Memory Requirements, and Execution Times
o
c
c
o *t*t***t*t'<t'<t^*^*t^^m*tm**t
E 6 >
o
u
z co
a
a o o
« M tOtOCOtOCOLOtOtOtOtOtOtOtOtO COCO
o zO mmmmmmmmmmmifliniinmmcnloLO
DC
6
©
U ttlANUujM^u.U)nQffi(D< i- 00 O)
-O CMCMCMCMCMCMCMCMCMCMCMCMCMCM CM CM CM
2 cf«5
oooooooooooooocoor^oo
•
00
z
6 >
«o
+ + + + +
CO CO CM CO CM
++++++
CM CM CM CM CM CM
+ + +
CM CM CM
'5
c
•
'S
<
c
a
a
«-
O
zo
M
+ + + + +
f~ r— to r« to
++++++
to ^- •? to ro r>
+
* ^+ m
+
X
Dc O O CO o
V << <
CO
cf«5
"""on
«-«-<«- to
<
to
co eo
< LU
o
to
ujQ
to <
co ,o
< UJ UJ
o
6 >•
**n*n co co co co co co co co co
Z CD
•a
• O
oc to
*
• 6
oo to r» co r> r^ in in r- co in m to
X 2O
LU
1% O
03
CO
00
cj
00
cf«S
--"O"
«- «- eo «- r»
< 00 00 UJQ
rvoau-r^r^oo <-> to to
oo u. u.
O
6 >
CO CO CM CO CM CMCMCNCMCMCM CM CM CM
Z CD
CO O
• 6
Q
mv ajMo co * *t to co r» »t ** in
2o
U O CO O
I«5
"O
•-•-UO W
•- *- o) t- o
<0000OujQ
ocnoootn O
to to
cooo
to ^^CO^-CM CMCMCM CM CM CO
• i it
O © O
1 ! U) IT) ^ U> CM CM CM 00 CM CM CO
E 00 zo
E 5
« U O CO O
o "O
»- «- O O O OS 00 LU to to (J
«- «- 00 •- CO 00O"- oo uu
o s
6 >
Z 00
-- - "
c
o O
CM CM CM CM CM CM CM
•
C zo
O
"O CO CO
^m
CD
.-
<<
* in UU
^- in
cf«S
«
oc
-
SSSSi3Si2iiBi!ni8MSSiiiisaiaai»iiiJSSsss
O u. h
6809 Assembly Language Programming C-3
w
• CO CO CO CO
o cm" cm" cm" cm"
c
c o s
o
E 6 >
• Z CD
• o
> So. H-
o «
<0
• '•5
zo
K
o
o •
•
a
5 §5
m 6 >
+++++++++
COCMCMCOCMCMCMCMCM
+
CM
+
CM
++
CMCM
+
CM
+
CM
++++++
CMCNCMCMCMCO
• X Z CD
e
+ ++ + + +
c o •
& + + + + + + + + +
(Oioim)«***e + + ++ + +
1X < zO
co <o ^
>* co to 4« «^iaio
• • Ml UJ
XI • u o
c Si < S]
3* OujUJOCMCOO'-OO
.-UJ<.-COCOCOCOCO
*•
CD
O
CO
<<
<UJ
CO
CD
CO
<D
CMcMl-.r~.QO
< UJ < LU UJ r-
o 8
6 > ^COCO^f CO CO CO COCO CO CO CO CO CO CO CO ^ ,
Z CD
1 ID o •
c
• 6 f^toeor- i>- r« r- mm p. r- in it> m if> cd r~
z CJ
UI
w Si u.
u- CO t
§3 O
• hi uj
u. in t-
o oo
h*
^
r*
o
r*
<<
m u.
en
r-
<o
r*
cMcMi^r-QO
oo u_ oo u. u. •—
COCMCMCO CM CM CM CMCM CM CM CM CM CM CM CM CO
6 >•
z to
o CO •5 S
s CO in ID CO CD CD CO >tf ^ CO CO >tf >* >* * in CO
o ID
zo
£
Q •"
o>
u.
2
§3 OLUUJO
— O 0> «- 00
o 1*
O o
O
<<
CJ)Q
CO
o
CO
O
CMCMI^I^QO
O) Q J- CD QQ
o S
<* CO CO «t CM CM CM CM CM CM CM CMCM
6 >•
•
5
Z ca
•> <*- CO
o •
1 - mm -
*""' cm cm co in
+ + + +
mmm cmcm
E Zo
e
UJ UJ
3 U 00
1" O UJ UJ
<-Ooo>-
O <<<
o ^f(0
oo
lOr-
«- co co co co
CMCM
co u
o S
z co
„ ..„ _„ „ __
c w- CO
• O • IO
ic zo CMCMCMCM^-CMCMCM CM CM CM CM CO lO CM
• '8
a
e
II 8SSS^^ J 53cc2cS^ gt1ga<co8Si23 J 3Sc e clg_ w SS x < iaQw
| E Si
<s Is
C-4 6809 Instruction Codes, Memory Requirements, and Execution Times
(S
s CM
e
c o 8
•
E Z 09
o
• u
> a H- (A
a O
a <o
ec
'V zo
5
O
• -e
a + + + + + + +
d > CM CM CO CM CM CM CM
'5
X Z 00
e c
• *O •
a + + + + + + +
1K a ir> in to 't "t co co
< Zo
oc o
-5 <
UL
(0
<OQ<o Q
u. u. CO
UJ r- UJ < CO
o S
6 > CO CO ^ CO CO CO CO
o z co
*-
oc O
CO
• 6 co co r»- in m r~ i>«
X
a S O£
z specification.
UI pulled.
O m
-o
u_ u.
u_ co
O oo
«- co u-
co
co
O
r-
or
register
pushed
CM CM CO CM CM CM CM
6 >.
z co
encoded
byte
«•- (0
CO O
s o in in co ^^ co co
Q zO an
each
u o en
details. for
-o
Ooo
u. u.
Q OlfffiQ
CO
0)
Q
O
taken. always
cycle
for
is is
o IS 22
<e CM CM CO CM one
6 >. branch
code
a Z co
plus
.2
a *- (0 Chapter
•o O the
object
• 6 CM CM Tt r-
if
E aa Zo in
cycles
E
a O applies
5
•o •a
O O
CO O
CO
CO
U.
•-
instruction's
instruction
requires
* 1 ^ CM CM >- •- •- parentheses
z co
in of
c instruction
9 O
CO OO in data
£C Z (J
«- CM CM CM CM CM
description
count
PUL
u_ u.
U
O 7 CO CO immediate
u_ O *- CO
co «- <- - Q
*Om cycle
or
the
PSH
C
(A
2 E II
i
*!
<s
a. o
O u. ii
D
6809 Instruction Object Codes
in Numerical Order
Note 1 . The post byte may be followed by two bytes, one byte, or no byte. See Appendix B and the discus-
sion of the post byte in Chapter 3 for more details. Appendix E lists all possible post bytes and the
operand forms that produce them.
Note 2. Some instructions have two mnemonics. In each such case, we show both forms, separated by a
slash (/).
Note 3. Appendix B displays the "indexed forms" for operands in the indexed and indirect addressing
modes.
Note 4. In the instructions EXG and TFR, the processor interprets the second byte (the immediate data) as
designating the source and destination registers.
Note 5. Inthe instructions PSHS, PULS, PSHU, and PULU, the processor interprets the second byte (the
immediate data) as designating which registers are to be included in the transfer of data to or from
the stack.
6809 Assembly Language Programming D-3
47 ASRA Accumulator
48 ASLA/LSLA Accumulator
49 R0LA Accumulator
4A DECA Accumulator
4C INCA Accumulator
4D TSTA Accumulator
4F CLRA Accumulator
50 NEGB Accumulator
53 COMB Accumulator
54 LSRB Accumulator
56 RORB Accumulator
57 ASRB Accumulator
58 ASLB / LSLB Accumulator
59 ROLB Accumulator
5A DECB Accumulator
5C INCB Accumulator
5D TSTB Accumulator
5F CLRB Accumulator
60 pp 1
NEG indexed forms Indexed / indirect
63 pp 1 COM indexed forms Indexed / indirect
64 pp 1 LSR indexed forms Indexed / indirect
66 pp 1 ROR indexed forms Indexed / indirect
67 pp 1 ASR indexed forms Indexed / indirect
68 pp 1 ASL / LSL indexed forms Indexed / indirect
69 pp 1 ROL indexed forms Indexed / indirect
6App 1
DEC indexed forms Indexed / indirect
6Cpp 1
INC indexed forms Indexed / indirect
6Dpp 1
TST indexed forms Indexed / indirect
6Epp 1
JMP indexed forms Indexed / indirect
6Fpp 1
CLR indexed forms Indexed / indirect
70 ss qq NEG adrl 6 Extended (direct)
73 ss qq COM add 6 Extended (direct)
74 ss qq LSR adrl 6 Extended (direct)
76 ss qq ROR adrl 6 Extended (direct)
77ssqq ASR adrl 6 Extended (direct)
78 ss qq ASL adrl 6 / LSL adrl 6 Extended (direct)
79ssqq R0Ladr16 Extended (direct)
7A ss qq DEC adrl 6 Extended (direct)
7C ss qq INCadr16 Extended (direct)
7D ss qq TSTadr16 Extended (direct)
7E ss qq JMPadr16 Extended (direct)
7F ss qq CLR adrl 6 Extended (direct)
80 dd SUBAdata8 Immediate
81 dd CMPAdata8 Immediate
82 dd SBCA data8 Immediate
83 dd dd SUBDdata16 Immediate
84 dd ANDA data8 Immediate
85 dd BITAdata8 Immediate
86 dd LDA data8 Immediate
88 dd EORA data8 Immediate
89 dd ADCA data8 Immediate
8 Add ORA data8 Immediate
8Bdd ADDA data8 Immediate
8C dd dd CMPXdata16 Immediate
8Dmm BSR label Relative
8Edddd LDXdata16 Immediate
90 qq SUBA adr8 Base page (direct)
91 qq CMPA adr8 Base page (direct)
92 qq SBCA adr8 Base page (direct)
93 qq SUBD adr8 Base page (direct)
6809 Assembly Language Programming D-5
A4pp 1
ANDA indexed forms Indexed / indirect
A5 pp 1 BITA indexed forms Indexed / indirect
A6pp 1
LDA indexed forms Indexed / indirect
A7pp 1
STA indexed forms Indexed / indirect
A8pp 1 EORA indexed forms Indexed / indirect
A9pp 1
ADCA indexed forms Indexed / indirect
AApp 1 ORA indexed forms Indexed / indirect
ABpp 1 ADDA indexed forms Indexed / indirect
ACpp 1
CMPX indexed forms Indexed / indirect
ADpp 1 JSR indexed forms Indexed / indirect
AEpp 1 LDX indexed forms Indexed / indirect
AFpp 1
STX indexed forms Indexed / indirect
BO ss qq SUBA adrl 6 Extended (direct)
B1 ssqq CMPAadr16 Extended (direct)
B2 ss qq SBCA adrl 6 Extended (direct)
B3 ss qq SUBD adrl 6 Extended (direct)
B4 ss qq ANDA adrl 6 Extended (direct)
B5 ss qq BITA adrl 6 Extended (direct)
B6 ss qq LDA adrl 6 Extended (direct)
B7 ss qq STA adrl 6 Extended (direct)
B8 ss qq EORA adrl 6 Extended (direct)
B9 ss qq ADCA adrl 6 Extended (direct)
BA ss qq ORA adrl 6 Extended (direct)
BB ss qq ADDA adrl 6 Extended (direct)
BC ss qq CMPXadr16 Extended (direct)
BD ss qq JSR adrl 6 Extended (direct*
BE ss qq LDX adrl 6 Extended (direct)
BF ss qq STX adrl 6 Extended (direct)
COdd SUBBdata8 Immediate
CI dd CMPBdata8 Immediate
C2dd SBCB data8 Immediate
C3 dd dd ADDDdata16 Immediate
C4dd ANDB data8 Immediate
C5dd BITB data8 Immediate
C6dd LDB data8 Immediate
C8dd EORB data8 Immediate
C9dd ADCB data8 Immediate
CAdd ORB data8 Immediate
CBdd ADDB data8 Immediate
CC dd dd LDDdata16 Immediate
CE dd dd LDUdata16 Immediate
DOqq SUBB adr8 Base page (direct)
D1qq CMPB adr8 Base page (direct)
D-6 6809 Instruction Object Codes
E
6809 Post Bytes in Numerical Order
Not* 1 : See Appendix B For addre; sing modes which the opere nd forms represen t.
examples, 19-17-26
DEY, 22-34
interrupt-driven programs, 19-16
Digital-to-analog (D/A) converters, 13-40-43
Direct addressing. See also base page
loops, 19-11
— 15 direct addressing
programming errors, 19-1 1
extended indirect, 3-14—16 Instructions that read and write memory, 13-11,
general description, 3-16— 19 14-3. 14-5. 19-14
illegal modes, 3-17, 3-35 Interchanges, 9-11, 19-22-23
memory requirements, B-l Intermediate carry flag. See Half-carry flag
notation, 3-19 Interpolation, 21-3
post-byte,3-17-18, E-l Interpreter, 1-12
6800 indexing, comparison with, 3-40 Interrupt disable flag, 3-5, 15-3, 15-5-6, 15-13-14
summary, B-l Interrupt overhead, 15-15, 15-27
time requirements, B-l Interrupt-related instructions, 15-6—7
unimplemented modes, 3-17 Interrupt response, 15-2 —4
Indirect indexed addressing, 3-17, 3-25 — 27 Interrupt service routines, 15-8—11, 15-13 — 33
Inefficiency of high-level languages, 1-11 communications with main program 15-10—11
Information-hiding principle, 17-14 debugging, 19-16
Inherent addressing, 3-6, 3-8 general versions, 15-30 — 31
Initial values in RAM, 2-9 keyboard, 15-17-20
Initializing variables, 5-1, 5-6, 6-4, 19-11-12 printer, 15-2Q-23
Input handshake, 12-5 — 6 real-time clock, 15-23-28
Input/output startup, 15-15-17
categories, 12-2 subroutine use, 15-13
chips, 12-14-15 teletypewriter, 15-28-30
comparison to memory, 12-1 transfer of control, 15-2
examples, 13-12-52, 14-5-6 Interrupt vectors, 15-2, 15-4, 15-10
instructions, 13-10— 1 table, 15-10
interrupt -driven examples, 15-15 — 30 Interrupts
I/O device table, 3-29-31, 3-34-35, 12-13-14 ACIA (6850), 15-8
I/O driver, 9-5 advantages, 15-1
INS, 22-39 breakpoints, 19-3
Inserting elements in linked lists, 9-7 characteristics, 15-1—2
Instruction execution times, C-2 — disabling, 15-2, 15-11-15
Instruction set, 1-1, 3-1, 3-7, 3-38, 22-1, A-2 disadvantages, 15-3
Instruction tables enabling, 15-2, 15-11-13, 15-17
execution times, C-2— executing general subroutines, 15-13
extensions from 6800 instructions, 3-39, 3-43 — 44 initialization, 15-12 — 13
frequently used, 3-2 instructions, 15-5 —6
generalizations of 6800 instructions, 3-43 nonmaskable, 15-2, 15-7
identical to 6800 instructions, 3-39, 3-42 overhead, 15-15, 15-27
implementations of missing 6800 operation PIA (6820), 15-7-8
codes, 3-44 polling systems, 15-2, 15-8 —9
memory usage, C-2— priority systems, 15-2, 15-24, 15-30—31
new instructions, 3-43 — 44 response, 15-2—4
object codes in numerical order, D-2— service routines, 15-8—11, 15-13 — 33
occasionally used, 3-2 6809 system, 15-2-7
operation code mnemonics, 3-39 vectored systems, 15-2, 15-10
post-bytes in numerical order, E-l Inverse, 4-11. See also ones complement
seldom used, 3-3 Inverting decision logic, 19-12, 19-17, 19-20, 19-22
summary, 3-38-39, A-2- 19 INX, 3-41, 3-44, 6-5, 19-13, 22-39
Instructions INY, 22-39
bit patterns, 1-2, 3-18, 4-3 IRQ input, 15-3, 15-5, 15-10, 15-14-15
definition, 1-2-2 JMP, 3-11, 5-14, 9-13-14, 10-6, 19-15, 22-39-40
effects on flags, 3-4-5, A-3-19 JSR, 22-41-42
execution times, C-2 — examples of, 10-6, 11-5, 11-10
extensions from 6800 instructions, 3-39, 3-43 — 44 execution time, 10-7
frequently used, 3-2 function, 10-1
generalizations of 6800 instructions, 3-43 lack of immediate addressing, 3-11
identical to 6800 instructions, 3-39, 3-42 operation, 10-5 — 6
implementations of missing 6800 operation return address, 10-5 — 6, 11-3 —4
codes, 3-44, 6-5, 22-1 Jumpand link instruction, 10-17—18, 22-36. See also
input/output, 13-10-11 EXG instruction
interrupt-related, 15-6 —7 Jump instructions. See also BRA, condition branch,
memory usage, C-2 — EXG, JMP, JSR, RTS, RTI, SWI, and TFR
new, 3-43—44 differences in addressing, 9-4, 22-40
object codes in numerical order, D-2 to D-6 EXG instruction, 22-36
occasionally used, 3-2 jump —4
table, 9-2
operation code mnemonics, 3-39, C-2 — immediate addressing, 3-11
lack of
recommended use, 3-1 meaning, 2-3
seldom used, 3-3 TFR, 22-73
summary, 3-38-39, A-2- 19 Jump table, 9-2 — 4, 22-40. See also case structure
1 1
Keyboard interface, 9-14, 13-8-9, 13-22-40 Limited state of processor, 15-3, 15-4, 15-14. See also
encoded keyboard, 13-8-9, 13-38-40 E flag, fast interrupt, RTI instruction
unencoded keyboard, 13-32 — 38 diagram, 15-4
Keyboard interrupts, 15-17 — 20 indexed offsets, 15-14
Keyboard scan, 13-34—38 Linear structure, 17-16
Link editor, 2-17
Labels
Link register, 10-17-18, 22-36. See also EXG
choice of, 2-4
instruction
definition, 2-3, 4-7
Linked lists, 9-7-9
field, 2-2-3
Linking directives, 2-9
first character, 3-46
Linking loader, 2-17
in jump instructions, 2-3 —4 List processing, 9-1—9
meaning, 2-3, 2-7, 2-9
Loader program, 2-17
reasons for use, 2-3, 2-4, 4-7
Local variable, 2-14
selection rules, 2-4
Location counter, 2-8-9, 2-11-12, 3-49, 7-6
6809 assembler, 3-45-46
Logic analyzer, 19-9—10
space after, 3-45
Logical I/O device, 12-13—14
truncation, 2-4, 3-46
Logical shift, 4-4, 8-14-15, See also LSR
with assembler directives, 2-6—10, 3-48, 7-6
Long branch instructions, 3-37, 5-10, 22-42 — 47
Lamp test, 13-23 — 25
Lookup tables
Language level, choice of, 1-12—14
arithmetic applications, 4-8—11
Latching, 2-1-3, 13-1, 13-39-40
code conversion, 3-28-29, 7-1, 7-4-6, 13-26
by 6820 P1A, 13-1, 13-39-40
I/O device assignment, 3-30, 3-34, 12-13
LBCC, 22-42 jump, 9-12-14, 22-40
LBCS, 22-42 keyboard, 9-14, 13-37-38
LBEQ, 22-42 reducing execution time, 21-4
LBGE, 22-42-43 saving memory, 21-3
LBGT, 22-43 tradeoffs involved, 4-10— 1
LBH1, 22-43 uses, 4-11
LBHS, 22-43 Loops, 5-1—4. See also do-while structure
LBLE, 22-43 debugging, 19-11
LBLO, 22-44 decreasing execution time, 5-14, 6-4, 6-6, 21-4
LBLS, 22-44 execution time, 5-1
LBLT, 22-44 flowcharts, 5-2 — 3
LBMI, 22-44 sections, 5-1
LBNE, 22-44-45 structures, 17-16-17, 17-19, 17-21-22, 17-26
LBPL, 22-45 LSL, 22-51. See also ASL instruction
LBRA, 5-10, 22-45-46 LSR, 22-51
LBRN, 22-46
digit shift, 4-4
LBSR, 22-47 division by 2, 8-15
LBVC, 22-47 normalization, 4-4, 13-31
LBVS, 22-47 testing bit 0, 13-14, 13-17, 14-5
LDA,B, 4-1-2, 22-47-8
effects on flags, 5-11 Machine-independence, 1-8 — 9
execution diagrams, 3-29, 3-31, 3-35 Machine language, 1-1—5, 1-12
LDD, 4-8, 22-47-49 Macro, 2-13-14, 19-13
LDS, 4-10, 10-3, 22-47 Macroassembler, 2-16
execution diagram, 3-11 Maintenance, 13-43, 1V-4, 18-13
LDU, 4-10, 9-7, 10-16, 11-5, 11-7, 22-47 Maintentance manual, 18-13
LDX, 4-9-10, 5-6, 9-7, 9-15, 22-47 Major changes in systems, 21-4—5
LDY, 4-10, 5-7, 9-7, 10-16, 22-47 Majority logic, 12-8, 13-30
LEA. See indexed addressing modes, .6800
also Manual mode, 13-8, 13-10, 13-43, 13-47
operation codes Manufacturer's mnemonics, 1-5
addressing uses, 6-5, 11-4, 11-8, 19-3, 19-6,21-3, 22-50 Mark state on teletypewriter line, 13-48—49
arithmetic uses, 6-5, 8-3, 8-6, 8-15, 11-8, 21-3, 22-51 Mask, 4-3, 13-13, 13-14, 13-30-31, 13-35
cleaning up the stack, 10-17, 11-8, 11-11 by bit position, 13-14
description, 22-49 — 51 notation, 4-3
space allocation, 10-17, 11-8, 11-10, 19-6 Maskable interrupt, 15-2 — 4
LED, 13-20-29 Masking example, 4-3 — 4
control of, 13-20-21 Master reset of 6850 ACIA, 14-3-5, 15-29
interface, 13-20-21 Matrix keyboard, 13-33 — 34
turn-on time, 13-21 Maximum count in loops, need for, 6-4
Length of registers, 3-3, 4-9 Maximum value
Letter offset, 7-3 example program 5-10—12
Letters and numbers, confusing of, 2-4 subroutine, 10-10—1
Letters, seven-segment codes for, 13-23, 13-26 Medium-speed I/O devices, 12-2, 12-5 — 8
Library routines, 2-4, 10-1, 18-9-12 Memory dump, 19-6 — 8
Lightface type, 1-1 Memory map, 18-7 — 8
66
5
Multiplication, 7-9, 8-1, 8-7-8 P register. See condition code register, flags
by power of 2, 8-1, 8-14-15 Parallel I/O, 13-16, 13-22, 13-32, 15-17-23
Multiplication example, 8-7 — 8 Parallel interface devices, 12-14—15. See also 6820
Multiplying by small decimal numbers, 7-9 Peripheral Interface Adapter
N (lag, 3-3, 3-5, 4-5, 5-12, 5-15, 13-11, 13-31 Parallel interface standards, 12-14
Names, use and choice of, 2-4, 2-7, 2-10, 18-2, 18- Parallel/serial conversion, 13-48, 13-51 — 52
National 5357 A/D converter, 13-44-47 Parameter lists, 18-8-9
NEG, 22-53-54 Parameters, 10-2, 10-7, 10-9, 10-11, 10-14, 10-16
Negative elements example, 5-9— 10 general passing techniques, 10-2, 11-3 — 13
Negative flag, 3-5 types, 1 1-14
BIT instruction, 13-31 Parentheses, 3-50
meaning, 3-5, 4-5, 5-11 Parentheses around addresses, 5-6
position in CCR, 3-3 Parity, 6-9-10, 12-8, 13-48, 13-52
signed numbers, 5-12, 5-15 Parity generation, 6-9-10, 12-8, 13-52
testing bit 7, 13-11 PASCAL, 1-8, 1-11
use, 3-5, 13-11, 13-31
Passing parameters —2
principles, 17-1
argument lists, 11-3 —8 review, 17-32 — 33
definition, 10-2 structured programming, 17-15 — 26
general methods, 11-3 — 13 top-down design, 17-26—31
in registers, 10-2, 10-7, 10-9, 10-11, 10-14, 11-3 Program logic manual, 18-13
in the stack, 10-2, 10-7, 11-8-13 Program loops, 5-1 —3
Pattern comparison debugging, 19-11, 19-17, 19-22
program example, 6-11 — 13 reducing execution time, 6-4, 21-4
subroutine, 10-12114 time/memory tradeoffs, 21-2, 21-4
PCR notation, 3-19, 3-25, 3-49, 10-17, 22-50 Program relative addressing, 3-23 — 25, 3-36—38
Pending interrupts, 15-8 Program speed, increasing, 21-4
Percentage sign, 3-49, 4-3 Program stub, 17-26-28
Peripheral interface adapter. See 6820 Peripheral Programmable I/O devices, 12-14—15. See also
Interface Adapter 6820 Peripheral Interface Adapter
Peripheral ready signal, 12-5, 12-7, 13-8, 13-11, 14-4 Programmable timer, 12-9
Physical I/O device, 12-13 Programmed I/O, 15-1
PIA. See 6820 Peripheral Interface Adapter Programmer's flowchart, 17-4
Plus sign, 3-19 Programming mode of 6809 processor, 3-3
Pointer, 5-3, 5-6 Programming time, division of, IV-3
Polling, 12-5, 13-11, 15-8-9 Pseudo-operations, 2-1, 2-5—10, 2-12—14,
definition, 12-5 3-46-48, 11-5, 3-46-48, 11-5
6820 PIAs, 13-11, 15-8-9 definition, 2-1, 2-5
of 6850 ACIAs, 15-8 general description, 2-5—10, 2-12—14
Polling interrupts, 15-2, 15-9-10, 15-29 mixing with instructions, 11-5
disadvantages, 15-9 standard 6809 assembler, 3-46-48
Portability, 1-7, 1-9 PSH, 22-57-58
Position, determination of,3-23-24, 10-17, 22-51 bit assignments for registers, 11-2 — 3
Return instruction, 10-1. See also RTI, RTS SETDP assembler directive, 3-48
Returning control to the operating system, 15-6, 22-71 Setting bits, 6-10, 13-10, 13-43, 15-5,15-30, 22-56
1 1
16-bit decrement in memory, 15-14, 19-3 write strobe, 13-7, 13-9, 13-26-29, 13-43
16-bit increment in memory, 8-15 6821 Peripheral Interface Adapter (PIA), 12-15, 13-1
16-bit instructions, 3-10, 3-13-14, 4-8, 4-10 6828 Priority Interrupt Controller, 15-10
autodecrement, 3-33 — 34 6840 Programmable Timer, 15-24
base page direct addressing, 3-11 6844 DMA Controller, 12-8
double accumulator instructions, 4-8, 4-11, 5-8 6846 Multifunction Support Device
extended direct addressing, 3-13 (ROM/lO/Timer), 12-9, 15-24
immediate addressing, 3-9—10 6850 Asynchronous Communications Interface
moving addresses, 9-6 (ACIA), 12-15, 14-1-6
operations on index registers and stack addressing, 14-1, 14-3
pointers, 4-10 block diagram, 14-2
transfers, 7-8 control register, 14-1, 14-3 —5
16-bit ones complement example, 4-11 features, 14-3—4
16-bit registers, 3-3-4, 4-8-10, 5-6, 10-16 initialization, 14-5, 15-29
choice of, 5-6, 10-16, 21-3 interrupt mode, 15-28-29
transfer to or from stack, 11-2, 22-57 interrupts, 15-8—9
16-bit shift, 8-12 master reset, 14-3-5, 15-29
1 6-bit summation example, 5-6—8
polling
6502 compatibility, 3-45, 10-5 power-on reset, 14-5
6522 Versatile Interface Adapter (VIA), 12-15 read-only registers, 14-3
receive routine, 14-5 temporary storage, 9-12, 10-9, 10-17, 11-8,
register contents, 14-3 —4 13-3, 15-13, 15-19, 15-30
reset, 14-3-5, 15-29 usual assignments, 5-6
status register, 14-3, 14-5 Stack pointer U, 3-3, 3-4
transmit routine, 14-6 difference from stack pointer S, 3-4, 22-58
write-only registers, 14-3 —4 index register, 3-17, 3-19, 3-23, 3-35^5-7, 8-3, 19-6
Slow I/O devices, 12-2 — 5 passing parameters, 10-16, 11-2, 11-5-7, 11-11
Software delay routines, 12-9—12, 13-46 subroutine linkages, 22-59
Software development Stack values, changing, 15-13115
coding, IV-3 Standard mnemonics, 1-5
debugging, 19-1-27, 20-5 Standard 6809 assembler (from Motorola), 3-45 — 50
documentation, 18-1 — 14 address field, 3-48-50
flowchart, IV-2 addressing mode notation, 3-49
measuring progress, IV-3 arithmetic and logical expressions, 3-50
problem definition, 16-1 — 14 automatic optimization of constant offset
program design, 17-1—34 mode, 3-22
redesign, 21-1-6 delimiters, 2-3, 3-45
stages, IV- 1—4 field structure, 3-45
testing, 20-1-6 labels, 3-46, 3-48
Software handshake, 15-11 pseudo-operations, 3-46 — 48
Software/hardware tradeoffs, 7-1, 12-9, 13-38, Start bit, 12-5, 13-48, 13-49
13-52-53, 15-27, 21-5 Start bit interrupt, 15-29-30
Software interrupt instructions, 22-70 — 71 Starting address of any array or table, 3-20, 3-28,
availability of SWI2 to end user, 15-6 3-30,4-9-10, 7-5-6, 8-7
breakpoint, 19-3—5 Starting code, searching for, 13-30
debugging use, 19-3 — 5 Startup interrupt, 15-15—17
decrementing return address after breakpoint, Statement, 2-1
15-14, 19-3 Static allocation oftemporary storage, 10-17
effects, 15-6 Status flag. See condition code register flags
reducing memory usage, 21-3 Status information, 13-29 31 —
transferring control to operating system, 15-6, 22-71 favored bit positions, 13-31
trap, 15-6 Status register
uses, 15-6, 19-3-5, 22-71 6809 CPU. See condition code register
vectors, 15-10 6850 ACIA, 14-3, 14-5
Software simulator, 19-8-9, 20-2 STD(S,U,X,Y), 22-66-68
Sorting example effects, 4-8
debugging, 19-21 — 26 moving addresses, 9-6, 11-4, 11-6, 11-8
program, 9-10—12 two-byte operation codes, 10-16, 22-68
testing, 20-4 Stop bit, 12-5, 13-48, 13-52
Sorting methods, 9-11—12 Storage requirements
Source code, 1-6 ASCII, 6-2, 6-8
Square brackets indicating indirection, 3-15, 3-45,3-49 BCD, 6-2, 6-8, 7-8
Space state, 13-48, 13-49 Stray interrupts, clearing of, 13-39, 13-47, 15-21
Spaces in 6809 assembler statements, 3-45 String comparison, 6-11 — 13, 10-12—14
Spaces in strings of characters, 6-5, 6-8 String editing, 6-5— 10
Speed, increasing of, 21-4 String length
STA,B, 3-11, 4-1-2, 22-66-67 program example, 6-3 — 4
Stack subroutine, 10-7-9, 11-4-6, 11-8-11
changing values saved in, 15-13—15 Strings of characters, 6-1 — 16
interrupts, 15-3 —5 Strobe, 12-5, 13-38
parameter passing, 10-2, 10-7, 11-8—13 Strobe signal from 6820 PI A, 13-7, 13-9-10,
subroutine return addresses, 10-1, 10-5, 22-59 13-26-29, 13-40
temporary storage, 9-12, 10-9, 10-17, 11-8, 13-31 Structured programming, 17-15 — 26, 18-7
Stack pointer, 3-3-4, 11-1-2 advantages, 17-19
Stack pointer S, 3-4 disadvantages, 17-20
argument lists, 11-3 — 8 review, 17-25
contents, 10-6 rules, 17-26
difference from stack pointer U, 3-4, 22-58 structures,17-15— 19
indexed offsets for registers, 15-13—15 switch and light system, 17-21
initialization, 10-3, 10-5 switch-based memory loader, 17-21 — 22
interrupts, 15-3 —5 terminators, 17-26
JSR instruction, 10-5-7, 22-41-42 use in documentation, 18-7
parameter passing, 10-2, 10-7, 11-8—13 verification terminal, 17-22 — 25
return address, 10-6 when to use, 17-20
RTI instruction, 10-6-7, 22-61-62 Structured testing, 20-2 — 3
RTS instruction, 10-6-7, 22-62-63 Structures. See data structures, structured programming
subroutine use, 10-5 — 7 Stubs, 17-26-28
SWI instructions, 15-6, 15-10, 19-3-5, 22-70-71 SUB, 7-7,8-5-6, 8-17, 22-68-69
SUBD, 4-14, 8-5, 22-68-69 SYNC, 15-6-7, 22-71
Subroutine documentation, 10-3 diagram, 15-7
examples, 10-5, 10-9, 10-11, 10-14, 10-16, 11-5, Synchronizing with I/O devices, 12-5, 12-8,
11-7, 11-10, 11-13 13-29-30
library examples, 18-9—12 Synchronizing with real-time clock, 15-23 — 24
Subroutine linkages Synchronous I/O, 12-8
hardware stack, 10-5-6, 22-41 Syntax, 1-10
index register, 10-17-18, 22-36
user stack, 22-59
TAB, 22-72
Table, lookup, 3-28-31, 4-8-11, 7-1, 7-4-6, 9-1,
Subroutine library, 10-1, 18-9-12
9-3, 9-5, 12-13-14. See also lookup tables
Subroutines, 10-1-20, 15-13, 18-9-12
comparison with macros, 2-3 Table of squares example, 4-8—11
delay, 12-10-12 TAP, 22-72
documentation, 10-3, 18-9-12 TBA, 22-72
errors in use, 19-13
TDRE flag in 6850 ACIA, 14-3-4, 14-6
Teletypewriter data format, 13-49
examples, 10-4-16, 11-4-13, 18-10-12
Teletypewriter interface, 13-48 — 53, 14-1—6
instructions, 10-1-2, 10-5-6
Teletypewriter interrupt, 15-28 — 30
interrupt service routines, use by, 10-2, 15-13
Teletypewriter output routine
library, 10-1, 18-9-12
linkages, 10-5-6, 10-17-18, 22-36, 22-41, 22-59 commenting, 18-5 — 7
macros, comparison with, 2-3 self-documentation, 18-1—2
Testing, 20-1-6
nesting, 10-17
aids, 20-2
parameters, 10-2, 11-4
passing parameters, 10-2, 10-7, 11-3—13 code conversion example, 20-1
data, selection of, 20-3
position-independence, 10-2, 10-17
definition, IV-4
reducing execution time, 21-5
reducing memory usage, 21-2, 21-3 debugging, relationship with, 20-1
reentrancy, 10-2
examples, 20-1, 20-4
review, 20-5
relocatabilily, 10-2
rules, 20-2-4
specifying parameters, 11-14
storage allocation, 10-17
self-checking numbers example, 20-5
sorting example, 20-4
types, 10-2
special cases, 20-3
Successive approximation A/D converter, 13-44
5-4 — 9, structured testing, 20-2 — 3
Summation example, 18-10—11
test data, selection of, 20-3
SWl,4-2, 15-6, 15-10, 19-3-5. 21-3-4, 22-70-71.
tools, 20-2
See also software interrupt instructions
vector, 15-10 Testing bits, 13-13-14, 13-30-31, 15-8-9,22-7
Switch and light system example; Testing examples, 20-1, 20-4
error handling, 16-5 —6 TFR, 22-72-73
flowchart, 17-4—5 direct page register, loading of, 7-7, 22-73
effects, 7-7
inputs, 16-4
modularization, 17-12 examples of use, 4-4, 7-7, 19-6
I llllll CD
BBB BBBUBB llllll III III >
8
BBBBB BBBBB BBBBBB CD
iSBN 0-931988-35-7 M -j