Beginning Assembly For The TI
Beginning Assembly For The TI
Beginning Assembly For The TI
'PP
1 -v.. ,
BEIN NI
fe
'
111
111111111111
TI
ii
HOME COMPUTER
No part of this boot . may be reproduced in any form or by any means, electronic or mechanical, including photocopying, without permission in writing from the publisher. Printed in the United States of America 1984
i.
INTRODUCTION
There is something really big underlying the BASIC language' Many gifted programmers have considered writing e:,citing games for the TI Home Computer only to be faced with the limitations of the cumbersome BASIC language. It does not take one long to realize that it is simply not possible to accomplish all that arcade style games entail using BASIC alone. BASIC is sometimes Just too slow. There is essentially nothing wrong with using BASIC if you re programming operations don't require a great deal of speed. But if you are writing programs which have a lot of things happening simultaneously, such as a number of obiects flying around the screen with the program trying to keep track of coincidence checks, BASIC Just can't do the ioh. BASIC by its very nature Lends to use up a lot of memory in a short period of time. For these reasons and the ones previously alluded to, you may want to consider adding program modules written in assembly language to your BASIC programs. Or even writing your complete program entirely in assemblv language. This boor is designed to help the beginner in introducing him or her to assembly language. The boor assumes that you have no previous egperience in programming other then BASIC. If you already r.now BASIC, that is fine. If you are already developing programs in assembly language, that is even better. This boor was designed as a study text. That is, it wa , ; meant to be read cover to cover, each chapter building on what was learned in the preceding chapters. If something is discussed that you do not quite understand after a thorough reading, go on as it will probably become clear in later sectaons. Take the time to complete the study questions at the end of each chapter. They will reinforce important concepts.
-1-
INTRODUCTION
This book begins with the fundamentals. Chapter 2 binary and hexadecimal numbering systems. It also important terms and concepts that will be carried boot, . Make sure you completely understand chapter proceeding.
GICIFAMINIT9: IEJF
EaDICIIK
This bool contains 14 chapters. In chapter 2 you are introduced to the counting system that the computer uses to keep trac . [ of numbers. You are also introduced to the hexadecimal system which greatly simplifies programming. Chapter 3 discusses the assembler, memory utilization and the internal registers of your Home Computer. It also explains how assembly language programs are developed and written. Additionally, you are introduced to the source statement, which is a programing line in assembly language akin to a BASIC statement. Chapter 4 introduces the instruction set. The -first topic ta[c.n for discussion is Addressing Modes, or ways to inform the computer e-actly where data or information can be found in memory. Subsequent sections of this chapter introduce you to the Instruction Set with each Instruction discussed at length as tu its usage and purpose. Numerous e:\amples e used to dramatize important points. ln Chapter 5 you learn about Assembler Directives. These consist of instructions to the assembler program that can significantly reduce program development Lime on your part. Chapter 6 discusses Utility programs in-depth. These are already constructed assembly language programs that are available to you. Again, numerous examples are provided to illustrate important points. Chapters 7, 8 and 9 discuss screen Graphics, Sprites and Sound control. You learn how to control complex screen graphics as well as how to incorporate sound into your programs. Prior to chapter 10 this book discusses how to create assembly language programs using the Editor/Assembler package. Chapter lo is a complete description of how to create assembly language programs using the lane-by-line assembler and the Mini-Memory module. Explicit instructions are gaven e.:plaining the differences and how to create programs that will run with either system configuration. Chapter 11 outlines the conversion of many BASIC commands into their assembly language equivalents. This is done to illustrate
INTRODUCTION
general assembly language concepts. Chapter 12 outlines BASIC support routines that are available. It explains how to linF BASIC programs wit.h assembly language programs. It also outlines how parameters are passed between the two types of programs. Chapter presents a brief description of tho advanced mathematical routines that are available. Linking to console resident routines is also discussed. This book provides four appendices for your convenience. Appendix A contains tables that aids in interchangind decimal and hexadecimal numbers. Appendix B outlines the TMS990n instruction Set. Appendix C lists the Assembler Directive set. Appendi:. D is perhaps the most interesting, it provides some source code for frequently used assembly language game modules. You can operate joysticks, simulate gravity, scroll the screen, create delays ect...
DID IL Li CT.:
1, 1
11
CONTENTS
Chapter 1: Introduction Chapter 2: How A Computer Counts Chapter 3: The Assembler 1 5 15 25 65 77 97 115 127 139 149 169 183 195
Chapter 4: The Instruction Set Chapter 5: Assembler Directives Chapter 6: Utility Programs Chapter 7: Graphics Chapter 8: Those Spirited Sprites Chapter 9: Let There Be Sound
Chapter 10: The Line-by-Line Assembler Chapter 11: Converting BASIC to Assembly Language
I r I
124
(Decimal)
>7C
(HEX)
This chapter is a basic introduction to computer numbering systems. It is aimed at those who have no or limited knowledge in this area. If you already understand these concepts and how they apply to assembly language programming, feel free jump ahead to the next chapter.
"he
The computer stores all the information contained within it in an area called the memory. Memory can be thought of as a large collection of electrical switches. Each switch can be either "on" or "off" and each can be set or reset by the computer as needed. Each individual switch can be thought of as the computers smallest single memory cell. This single memory cell is known as a BIT which is short for Binary DIgiT. A bit holds the smallest piece of information that the computer can handle. A bit is either on or off, true or false, plus or minus. It has no in-between states. The On and Off settings of the memory bits correspond to the two digits that make up the binary numbering system. The binary system consists of the two digits 0 and 1 and is the fundamental system the computer uses to keep track of numbers. The digits are represented by 0(Off) and 1(On). In your Home Computer groups of eight bits are lumped together to form a single byte. It might be easier if you think of a byte as a row eight lightbulbs mounted on a long board. Each lightbulb represents a single bit and can be either on or off. The entire board with its eight lightbulbs is taken as one byte. In the following sections we will see how the computer can use these bits and bytes to store information.
Looking at the above illustration of our byte we see that each of the lights (bits) are currently turned off. From this we can say that the byte is representing zero value. In computer language it is said to be "holding" a zero. Now consider that we want this byte to represent the number one instead of zero. As we watch the light (bit) on the far right comes on:
The column on the far right of our byte is the one's column and hence the byte on the preceding page would represent or "hold" a value of one. If we wanted our byte to hold a value of two instead we would turn on the next bit in the row like so:
And to represent the number three we simple add the values of the last two bits together like so:
By simply looking at a byte, checking to see which bits are turned on, and adding their values together the computer can tell the value of the number being held there. Each bit has its own special position on the byte. Starting on the right and proceeding to the left, each bit is worth twice what the one before it was. Another way to think about it is to consider each bit (from right to left) as an increasing power of two. Thus the rightmost bit is 2 to the power of 0 or 1, the next bit is 2 to the power of 1 or 2, then next 2 to the power of 2 or 4, and so on until the leftmost bit is reached which is 2 to the power 7 or 128. By adding combinations of bits that are turned on together the value of any number from 0 (all bits off) through 255 (all bits on) can be represented:
Lets review, eight bits together make up a single byte. A single byte can hold any value ranging from 0 to 255 decimal. The following examples are binary (byte) representations of some decimal numbers. Keep in mind that each 1 or 0 represents a bit that is either ON(1) or OFF(2). The bits are divided into two groups of four bits each to make them easier to read: BBNARY
-----------
DECIMAL
34
0100 001 0
(64)+(2).=
66
Normally you would not have to add binary numbers together when programming, this function being performed by the computer. However, to provide a complete presentation we will briefly discuss the addition of binary numbers. When adding binary numbers together you follow essentially the same procedure as when adding two decimal numbers together. For example, when adding the values 6 and 8 together you must carry a 1 into the "tens" column in order to arrive at the correct result of "14". Similarly, when the two binary digits 1 and 1 are added together, a 1 must be carried into the two's column. Thus the addition of 0000 0001 with 0000 0000 becomes 0000 0001 and the addition of 0000 0001 with 0000 0001 becomes 0000 0010. The following illustrate some further examples of binary addition:
*
1 0101
+_0001 011.0
**
11
0111 + 0110 1101
**
11
*
1
*carried l's
The first problem involves a carry of one from the first column to the second (1+1). This carries over to the second column which contains only two 0's. Adding the carried 1 makes the result under this column a "1".
a certain value that was determined by its row position on the byte. To make them easier to refer to, bits are numbered 0 through 7 starting on the left and proceeding to the right (in contrast to their value which increases from right to left). The numbering of bits is illustrated below:
9 S
,C 7
Bits are also said to become more significant as they increase in value. That is, bit 7 is considered the least significant bit (LSB), and bit 0 is the most significant bit (MSB). Also, bit 0 is more significant than bit 1 and bit 1 is more significant than bit 2 and so on down the line. Significance than is tied to the relative value of a bit. As the relative value increases, so does the bits significance as illustrated below: \I! //
1:)
..".1*0"
When a byte holds a signed number, only the 7 least significant bits hold the value of the number (bits 1 thru 7). The most significant bit (bit 0) is reserved and is used to indicate the sign of the number being held. If this bit is set to "1" then it indicates that the number being held is a negative number. If this bit is reset to 0 then it indicates that the number being held is a positive number. As you may have already guessed, a byte that holds a signed number uses bit 0 to hold the sign. Therefore it can't hold as wide a range of values. Bytes holding positive numbers can only hold values ranging from 0 (binary 0000 0000) to 127 (binary 0111 1111) while bytes holding negative numbers can hold values ranging from -1 (binary 1111 1111) to -128 (binary 1000 0000). You may be wondering why -1 is represented in binary as 1111 1111 instead of 1000 0000. The reason for this is that negatively signed numbers are represented in what is known as their 2's compliment form. By using 2's compliment to represent negative numbers the dilemma of having zero be represented by all 0's (positive zero) and all O's with a 1 in the sign position (negative zero) are avoided.
10
To find the binary representation of a negative,number (that is, to find its two's compliment form) simply reverse each bit, that is change each 1 to 0 and each 0 t 1, then add 1 to the o result. The following example illustrates how to find the 2's compliment representation of -65: 0100 0001 1011 1110 1011 - iii1 +65 Reverse all bits. Add one. -65
The reverse procedure (reverse all bits and add 1) can also be used to find the positive form of a negative number.
wolIR-AD13
A bit is the smallest piece of information that the computer can hold. The computer lumps 8 of these bits together to form a single byte which it can use to store usable information. By now you should begin to see some limitations with this system. For example, using bytes alone you could only represent unsigned numbers whose values range from 0 to 255 or signed numbers whose values range from -128 to +127. To represent numbers larger than this we must devise some alternate scheme. The simplest approach would be to hook two bytes together in order to form a larger number of bits from which to draw information. Two bytes hooked together in this fashion are referred to as a single WORD. The left byte contains the first 8 bits that make up the left-half of the "word" while the right byte contains the second group of 8 bits that form the right-half of the "word". The bits are numbered consecutively left to right from bit 0, the left-most bit on the left byte, through bit 15 which is the rightmost bit of the right byte. The value of each bit is double as we move from right to left along the bits. For example:
lEc
-11-
INIUMEclaFc=
0 4 3 7
Q's dry
11
49
24
2 Xi
A4
Notice that by linking two bytes together in this manner to form a single word v%). can now represent a much greater range of
11
numbers. To sum up, in your Home Computer most chunks of information are processed in units referred to as words. Each word is made up of two bytes. Each byte is made up of eight bits. For words that contain signed numbers, bit 0 (the left-most bit of the left byte) is used to hold the sign of the number. Words can hold signed values that range from 0 (0000 0000 0000 0000) to 32,767 (0111 1111 1111 1111). Words holding negative numbers can hold values ranging from -1 (1111 1111 1111 1111) through -32,768 (1000 0000 0000 0000). Keep in mind that negative numbers are represented in their two's compliment form. The following is a graphic representation of -4356:
1.7" z...
-
When computers were in their infancy programmers had to enter each byte of binary code by hand. Not only was this a very tedious and time consuming process, but it was extremely prone to error as well. For example, a binary number like 0000 1110 could easily be transposed into the entirely new value 0000 1101. The HEX system (short for hexadecimal) was designed to speed up the process of writing in binary code. The following chart compares the Decimal, HEX, and Binary numbering systems:
DECIMAL o 1
CI -0, C,4t..)
HEy. >oo
>01 >02
>07:
BINARY
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001# 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
7 8
9 10# 11 12 13 14 15
>04 >05 >06 >07 >08 >09 >OA >OB >OC >OD >OE >OF#
12
Note that (#) signifies that the digits begin to repeat on the preceding page (10's decimal, 16's HEX, 2's binary). If you study these systems you find that in decimal you begin 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, then start again in the 10's column: 10, 11, 12, 13, 14, ... and so on With HEX you count >0, >1, >2, >3, >4, >5, >6, >7, >8, >9, >A, >B, >C, >D, >E, >F, then start again in the 16's column: >10, >12, >13, >14, >15, ... >18, >19, >1A, >1B, >1C, ... and so on. In both decimal and hexadecimal numbering systems the individual digits have some "weight" which is a power of the base. In the HEX system the base is sixteen so each digit has a value 16 times the value of the digit to its immediate right (as opposed to the decimal system where each digit has a value 10 times the value of the digit to its immediate right). For example, the hexadecimal number >4CEF has a decimal value of 19,695 because:
(4x16 )+(Cx16 )+(Ex16 )+(Fx16 ) = 19,695 reduces to the decimal form: (4x4096)+(12x256)+(14x16)+(15) = 19,695 where C=12, E=14, and F=15 from the table on page 11. When writing in assembly language all HEX numbers are designated with a "greater than" sign (>) in front of them to differentiate them from decimal values. The following are some HEX equivalents of decimal values:
HEX
>0A >AA >B3F >FFFF >FE03 >0214
BINARY
0000 0000 0000 0000 0000 0000 1010 1010 0000 1011 0011 1111 1111 1111 1111 1111 1111 1110 0000 0011 0000 0010 0001 0100
SIGNED NUMBERS -4 1111 1111 1111 -23 1111 1111 1110 8 0000 0000 0000 32,767 0111 1111 1111
Learning to work with hexadecimal numbers is perhaps the biggest hurdle to get over when trying to master assembly language. You should not be disillusioned if everything is not
13
crystal clear up to now after all, this counting system is unnatural. You should spend some time now practicing the exercise at the end of this chapter. You should at least be fluent in converting hexadecimal numbers into their decimal equivalents and vice-versa before proceeding even if you don't quite understand what is going on yet. To sum up, in order to figure out the decimal value of a HEX number, simply multiply the second digit by 16, the third by 16 squared the fourth by 16 cubed and add all four values together. Thus >12A becomes (1x256)+(2x16)+(10x1)=298. HEX at first does seem impossibly confusing. Do not let this discourage you as the system will probably become second nature to you after you have worked with it for awhile. You can quickly look up HEX values that you need in a hurry in Appendix A at the end of this book. Remember, all HEX numbers are distinguished by placing a "greater than" sign (>) in front of them: >OA or >1222.
14
(D) -10,250
7.
1110 1101
(c)
1001
.=.
in hexadecimal
4.
List the decimal equivalent of >1C34 if (A) The value represents a signed number. (B) The value represents a unsigned number.
3 THE
In the last chapter we learned that the computer speaks in a binary code. We also learned that binary code is the most efficient and fastest executing language. In addition, we learned an alternate method of designating numbers; that being the hexadecimal system. Early on programmers found it difficult to program instructions into the computer using binary codes. For instance, to enter the instruction that would add two numbers together required having to type in the binary code 1010 0000 0000 0000, or the HEX equivalent, >A000. Likewise, to enter the subtraction instruction required having to enter the binary code 0110 0000 0000 0000, or the HEX equivalent, >6000. As can be easily seen, this is not only a time consuming process, but is extremely prone to error as well. Eventually someone got the idea to replace the binary commands with english abbreviations that programmers could easily remember. In this way an addition instruction could be typed in as "A" instead of 1010 0000 0000 0000, and a subtraction instruction could be written as "S" instead of 0110 0000 0000 0000. A separate program referred to as the "assembler" is then used to convert these abbreviations into their binary equivalents. When a program is first written in this "assembly language" it cannot be run on the computer yet since the computer does not understand the abbreviations. Before a program can be run it must be assembled by the assembler program. There are thus two versions of an assembly language program. The first version written by you using the abbreviations is termed the source program (or source code) while the second binary version created by the assembler program is termed the object program (or object code). In summary, the purpose of the assemble program is to convert the source code which you have written into object code which the computer can understand.
-15-
16
THE ASSEMBLER
:T.-
C7 -01I
Before we advance too far into assemble language programming proper, it would be useful for us to discuss how the computer keeps track of instructions and how it follows through with them in a neat, orderly manner. The electronic brain of your computer is the TMS 9900 processor. It has the capability to perform a wide variety of tasks quickly and efficiently. If we couid look down into the computer we would be able to see distinct areas that serve specific functions. One area is called RAM which stands for Random Access Memory. RAM contains a large number of free bytes. You can, as the name implies, randomly access any of the bytes located here. This is the area where your program instructions are stored when you type them into the computer. Thus, RAM can be though of as a blank slate waiting for you to type in information. Another area is referred to as ROM which stands for Read Only This is an area where the computer permanently stores a set of instructions that it can refer to when needed. For instance, when you type in a BASIC command, ROM is where the instructjons that translate the BASIC command into binary code reside.
Memory.
The third major area of the computer is termed the CPU or It is the heart and soul of the computer. The CPU continuously takes in numbers from memory locations all over the computer. These numbers can then be sent out unchanged to other locations, or they can be compared, added to, or otherwise modified before being sent back to RAM or ROM. The CPU can perform all these tasks with the help of some special "tools". These tools are referred to as Registers. A Register can be thought of as a memory word that is reserved for a specific purpose (remember, a word is made up of 2 bytes hooked together). Registers located in RAM that you can alter during programming are referred to as Software Registers. Registers located in ROM that can be used only by the CPU are termed Hardware Registers. A set of sixteen consecutive Registers is referred to as a Workspace.
It may be helpful to think of a Register as an area of memory where you can store information that you want the CPU to perform some operation on For example, suppose you wanted to add two numbers together. You would first place the values to be added in two Registers and then instruct the computer to add them together and place the sum into a third Register. Registers can be located anywhere in RAM as long as you tell the computer where they are. In later chapters we will discuss how this is done. In your Home Computer you have a total of sixteen Software
Registers (termed a workspace) available to you. Each Register is
THE ASSEMBLER
17
one word (2 bytes) in size. These sixteen Registers are numbered RO through R15. These sixteen Registers are collectively referred to as your Workspace Registers. In addition to the Software Registers available to you there are three Hardware Registers that are used by the CPU to keep track of things. These are as follows:
1. 2. 3.
The following sections describe the three Hardware Registers in great detail.
IBIe -riE:F:
(P-G)
The Program Counter Register (PC) keeps track of the location of the next instruction to be executed by the CPU when it is running a program. In this way a sequential and orderly flow of instructions is maintained.
1F.ZIE: I S -Fla.F.: .
<WIF")
The Workspace Pointer Register (WP) keeps track of the location in memory of the current Software Workspace. This is the pointer that informs the computer where your Software Workspace area begins in RAM. Each byte in RAM is numbered so that the computer can find it. This number is referred to as the Address of the byte. This is similar to how the location of each house in a large city is designated by its street address. With this in mind it can be stated that the Workspace Pointer Register holds the beginning address of the current Software Workspace.
The Status Register is important in that it reports to the CPU about the current Status of things. For example, when the computer compares two numbers together it is useful to record the result of this comparison somewhere in memory. That is the purpose of the Status Register; it "holds" the information long enough for the CPU to make a decision based on it. Remembering that a Register is made up of sixteen bits, the Status Register reports various status conditions in the first six of its bits (0-5). The four least significant bits (12-15) hold information important towards interrupting the computer; but we will have more on interrupts
18
THE ASSEMBLER
later. Bits 7 through 11 are not used by the Status Register. Each bit in the Status Register can that signals some piece of information bit is set to 1, it signals to the CPU or ignore it depending on your program be thought of as a flag to the CPU. Every time a which may act on the flag, instructions.
The following figure demonstrates how the "flags" are arranged in the Status register:
BIT 0: LOGICAL GREATER THAN (L>), is set to 1 if a larger unsigned number is compared to a smaller unsigned number. BIT 1: ARITHMETIC GREATER THAN (A>), is set to 1 if a larger signed number is compared with a smaller signed number.
EQUAL (EQ), is set to 1 when two numbers being compared BIT 2: are equal. The equal bit is set regardless if the comparison is between two signed numbers or two unsigned numbers. BIT 3: CARRY (C), is set to 1 if an add operation produces a carry or if a subtraction operation produces a borrow of bit 0; otherwise it is reset to O. The Carry bit also holds the value of a bit that has been rotated or shifted out of a Register or Memory location. BIT 4: OVERFLOW (OF), is mainly an error indicator. It is set to 1 when the addition of two like signed numbers, or the subtraction of two oppositely signed numbers, has produced a result that is too large or small to be represented correctly by a single word.
Additionally, the OF bit is set to 1 if, during an arithmetic left shift, the most significant bit of the Register being shifted
THE ASSEMBLER
19
changes value. Also, during divide operations the OF bit is set to 1 if the most significant 16 bits of the dividend are greater than or equal to the divisor.
BIT 5: ODD PARITY (OP), is set to 1 when the parity of the result of a byte operation is odd. The OP is reset to 0 when the parity of the result is even.
The parity of a byte is said to be odd when the number of bits contained within it having a value of 1 is odd. For example the byte 0001 1111 is said to have odd parity because it has an odd (5) number of bits set to 1. Even parity is just the opposite.
BIT 6: EXTENDED OPERATION (X), is set to 1 when software implemented extended operation is initiated. However, the instruction XOP (for extended operation) is not available on all Home Computers. The only way to see if your computer supports this instruction is to try it. BITS 7-11:
-
UNUSED
BITS 12 15: INTERRUPT MASK, allows the TMS 9900 to recognize interrupt requests from peripheral devices hooked into the system. If the peripheral device has a level number less than or equal to the value in the interrupt mask, it is permitted by the CPU to interrupt a running program. Thus, if the four bits making up the interrupt mask are set at 2 (0010), then any device with a level D, 1, or 2 may interrupt a running program. In your Home Computer the interrupt mask is always set at 2 (0010). Because of this only values of 2 and 0 are useful.
Everybody has interruptions in their lives. Some of these are necessary such as when a newborn cries for food, you must stop what you are doing attend to the infants needs. While other times you may be to busy to be interrupted, such as when the phone rings during your favorite T.V. show; you may choose to let it go unanswered! The same is true for the computer. Sometimes peripheral equipment needs information from a running program and interruptions are the only way they can get it. Also, some ROM routines such as automatic sprite motion or sound generating routines need to be able to interrupt your running program in order to execute.
When you first turn on the computer all the Status bits are reset to 0. Don't worry if your not quite sure yet as to the significance of the Status Register, it should become clearer as we progress.
20
THE ASSEMBLER
F1RADIFRIPIMB
When first putting a program together from scratch you should follow a certain logical sequence of steps. These steps are summed up below: 1. Decide first exactly what it is you want the computer to do. Rough diagramming a "plan" of the program, referred to as a flowchart, helps get your thoughts together. Start putting the instructions (referred to as source statements or code) down onto paper. Enter the instructions into the computer through an Editor program which we will discuss in greater detail later. Convert the source code you have written into object code that the computer can understand using an assembler program. If the assembler finds any errors, correct these and reassemble. Run the program on the computer. If it performs differently than what you had expected, you must debug the program. This involves taking a copy of your source code and changing it until you can get the program to run right.
2.
3.
4.
5.
mia
The Editor is 'a program that we have not mentioned yet. The Editor program allows you to write out your source code and edit it directly on the screen before assembling it. The Editor program also allows you to save an incomplete source program on disc for later revision. This book assumes that you are already familiar with the Editor program. If you are not sure, refer to the instructions in the beginning of the Editor/Assembler manual that accompanies the software. If you are using the mini-memory module and line-by-line assembler refer to chapter 10.
fs-AoluIR.IDEE cf...DIDE:
Now that we have a general understanding about how to go about constructing source code, it is time to proceed along the specifics; namely creating a program. The source code is a logical sequence of instructions designed to guide the computer along a desired course. A source statement can be categorized as an instruction, pseudo operation, or an assembler directive.
-
THE ASSEMBLER
21
As we have mentioned before, an assembly language abbreviation (instruction) is a symbolic representation of a binary instruction. It is translated literally by the assembler program during the assembly process. Pseudo-operations and assembler directives give directions to the assembler program (not the computer) as to what to do with certain instructions or data. Assembler directives, pseudo-operations and assembly language instructions will be covered in greater detail in future chapters.
C:".", C11 NI
I INI F" Ft: C3 B Ft: int 141 ri I !NJ constants into the computer you may use
1.
DECIMAL --
Entered as a base ten number. May be an unsigned number from 0 through 65535, or a signed value ranging from -32768 through 32767.
123 -2410 65535 2. HEXADECIMAL -Entered as a string of up to +our alphanumeric (A thru F) characters preceded by a greater than (>) sign. The following are valid examples of hexadecimal constants:
>OF >1AC >32FD 3. CHARACTER CONSTANTS -Entered as a string of ASCII characters enclosed in single quotes; for example 'A' or 'AD'. A character constant consisting of only two quotes (no characters) is also valid. The following are valid character constants:
Phac:t.Pr. '2'
(7
,:on0=NA
el!:-.)
1 (50)'
Yajqqs
'AB'
'307.'
'HELLO !' 4.
1 (65)(66)' '(51)(48)(37)' ' (72) (69) (76) (76) (79) (32) (33) '
ASSEMBLY-TIME CONSTANTS --
These constants are defined at the time of assembly. The are written in the operand field of an EQU instruction. We will spend more time explaining how these constants are used when we reach this instruction in later chapters.
THE ASSEMBLER
Negative numbers are also easily specified. If the constant is in decimal form simply precede it with a minus sign (e.g.-23). If the number is in hexadecimal notation you must enter it in its two's compliment form. For example, -42 and >D6 both represent the same value.
MC:
(:31._
"1-sickMMIET4 -11-
Each line in an assembly language program is referred to as a source statement. Each source statement contains up to four Fields separated by a single blank space. The fields are positioned as follows:
Of these four fields, only the op code field is always required for a valid source statement. The other fields may or maynot be required depending on the op-code used. The maximum length of a source statement is 80 characters, however only 60 of these will be displayed when using a list file. The first character typed on a line begins the label field. If you do not use the label field then the first character must be a blank space. All the fields are separated by at least one blank space. The following is an example of a single source statement that uses all four fields:
-
MYREG BSS
>32
The following sections will describe the four fields that make up a source statement.
IL_IrA]BEA__ V- I E... L_Eli . The label field is a name or label that you give to a source statement so that you can refer back to it. This label can then be used in other instructions to refer back to it. For example, when you instruct the computer to jump from one instruction to another, you give its destination by specifying its label. Unless the first character is a blank, the first character in a source statement begins the label. It can be up to 6 characters in length. A label can be made up of any alphanumeric characters, but the first character must always be alphabetic. If you elect to omit the label field the first character of the source statement must be a blank space. Also, you are not allowed to put a blank space in the middle of a label; ie: MYREG not MY REG.
23
a 1...... ID
known as the one to four letter acronym for the microprocessor instruction. When the assembler program is run it uses an internal reference table to translate each acronym into the appropriate binary code. The type of op-code used determines how many and what type of operands should be found in the operand field.
The op-code field (short for operation code) is also mnemonic field (pronounced knee-mon-ik). It holds the
10F.*IFc Pt Ni r)
F- I
la L.... ID
The operand field contains the data or the location of the data needed by instruction in the op-code field. Some op-codes do not require an operand while others require one or more. If more then one operand is required they are separated by a comma. The operand field may contain one or more terms, expressions, or constants depending on the needs of the instruction in the op-code field. To sum up, the operand field contains the data that the instruction in the op-code field refers to. For example, in this ADD operation:
RO I R1
the ADD (A) instruction refers to the addition of the value in Workspace Register 0 to the value in Workspace Register 1.
The comment field is an optional field that begins one space after the operand field ends. It is always begun with an asterisk (*). The comment fields contains comments written by the programmer as a reminder to what the source statement does. These statements are ignored by the assembler program during the assembly process. Comments are utilized to remind you what the function of a source statement or group of source statements is. For example, the statement:
MYWSP EQU
>8300
reminds you that your workspace was begun at the specified address in memory. Comments can also stand alone on a line if the line begins with an asterisk (*). In this way entire blocks containing just comments can be constructed: ************************************************ * * * DEFINE EQUATES * ************************************************
24
THE - ASSEMBLER
74:1
CHAPTER
STUDY EXERCISES
1. What is the name of the program that converts sourFe code into ti# 'object code? 0 42. A Software Workspace area consists 'O-( how many registers? 3. Which bit of the Status Register is set when the result of arithmetical expression is too large to be represecited ih two's compliment form? 4. Regarding the four fields in the source statemeht? (a) (b) Which three of the fields may be optona_1? : _ Which character always begins a 3ine of comment or the first letter in a comment field. Which field of a source statement is al I ways.requi -P red? ,
is
(c)
5. What is the difference between an assembler directive and a instruction. 6. Is the followinga valid_he,xadecim,al,number? . ,
ti
t".4
6 0
>DEFG
.t7
7. Which portion of a source statement ,determines which and what type of operands are required.
;7,
re m ;,
-;
V
*.f
-I
';-
tri
=4 .5
"3
1. WORKSPACE REGISTER AND IMMEDIATE ADDRESSING 2. WORKSPACE REGISTER INDIRECT ADDRESSING ... SYMBOLIC REGISTER ADDRESSING 4. INDEXED MEMORY ADDRESSING 5. WORKSPACE REGISTER INDIRECT AUTO-INCREMENT ADDRESSING
The operand is the actual value that is to be "operated on" by the instruction. How you want to specify the operand determines the addressing mode that you will use. In the sections that follow each addressing mode is discussed in detail. An example is provided of each modes usage.
-25-
Zez
VII C3 Fc IF< ', F" ite:4 IC E IF: EGIB -11- IR: enk ID Ell IR: 1E 9-. 9 I NI In Workspace Register Addressing The operand is located in the specified register. Remember that a Workspace consists of sixteen consecutive Registers labeled RO through R15. Workspace Register 5 would thus be referred to as "R5". You specify in the beginning of your program where these registers will be located in RAM. We will have more on this later. An example of Workspace Register Addressing is the statement:
MOV R2,R4
which moves a copy of the contents of Workspace Register 2 (R2) into Workspace Register 4 (R4). Another example:
R6,R7
adds the contents of Workspace Register 6 (R6) to the contents of Workspace Register 7 (R7). The result is then placed in R7. When using Workspace Register Addressing Mode it is important to remember that the operand is found in the Register specified. :I. Pi pi 1E: ID :11: ons "T. P.' onk 13 ID Fi: E !E73 E3 I: NI C" :3
-
You can also specify a constant as a source operand. In this way the value is right there for the assembler to get and does not have to be located in a Register or found at another address. This is termed Immediate Addressing. An example is the following statement:
LI
R0,324
which places (loads) the value 324 into Workspace Register 0, and the statement:
LI
R9,>144
which loads the value >144 (324) into Workspace Register 9, and the statement: LI R6,-32
which loads the value -32 into Workspace Register 6. NOTE: Remember when using signed numbers the most significant bit holds the sign of the number. This limits signed values to numbers that can be represented with only 15 bits. The signed values thus range from +32767 (>7FFF) to -32768 (>8000). Unsigned numbers, however can range from 0 (>0000) Lo 65535 (>FFFF) since bit 0 does not have to be used to hold the sign of the number.
27
I rq ID I IFC
-11- IA ID ID FZ.
I t 10
With this type of addressing, the register specified contains the address of the operand instead of the operand itself. An indirect Workspace Register Address is preceded by an asterisk (*). For example, the statement:
MOV *R3,*R0
copies the word at the address given in Workspace Register 3 into the address found in Workspace Register 0. Notice how both R3 and RO are indirectly addressed, that is they both contain the address of the information rather then the information itself. Another example is the statement:
A *R4,R6
which adds the contents of the word being held at the address given in Workspace Register 4 to the contents of the word in Workspace Register 6. The result is then placed in Workspace Register 6. Notice how in this case R4 is indirectly addressed while R6 is directly addressed.
I NI ID I IF:
rA
Fel ff.: NI in
E3 NI C3
With this type of addressing the register specified contains the address of the operand as with indirect addressing. After the address is obtained from the Workspace Register, the address in the Workspace Register is incremented by 1 for a byte instruction or by 2 for a word instruction. This allows you to access data in memory in a sequential manner from a given starting point. A Workspace Register auto-increment address is preceded by an asterisk (*) and followed by a plus (A-) sign. For example, the following statement:
A *R3+,R1
adds the contents of the word found at the address given in R3 to the contents of Rl. The result is placed in R1. The address in R3 is then incremented by two ('A' is a word instruction). Another example is the statement:
MOV R9,*R10+
which copies the contents of R9 into the address given in R10 and increments the address in R10 by two. Now lets consider an example using real values. Suppose R1 contains >0004 and R2 contains >000A and address >0004 contains the value >0010, then the statement:
A *R1+,R2
adds the value found at address >0004 which is >0010, to the value found in R2 which is >000A. The result, >001A is placed in R2. The value in R1 is then incremented by two (A is a word instruction). Thus, after completion of this statement R1 contains >0006, and R2 contains >001A.
miampliFey AnniFoIp41E3
This type of addressing allows you to use a symbol to represent the address that contains the operand. The symbolic memory address is preceded by an "at" character (@). For example, if RO contains >0002 then the statement:
@JOYI,R0
adds the contents of RO with the contents at "JOYI" (in this case >00FF) the result, >0101, would then be placed in RO. Another example is the statement:
MOV @>AA03,@>0E3F
which copies the word at address >AA03 into location >0E3F.
1-11-1o1F
With indexed addressing, the effective address is gotten by adding the value of an index register to a displacement variable. You often use this addressing mode to access elements in a table. In such a case the value in the index register points to the beginning of the table, and the displacement to an element in the table. The indexed memory address is preceded by an "at" sign (@) after which comes the displacement value followed by the index register which is closed in parentheses. For example,
@4(R4),R1
gets the word found at the address computed by adding 4 to the address in R4. This word, in turn, is added to the word found in Rl. The result is then placed Rl. Another example in the statement:
MOV R5,@TABLE+3(R7)
which copies the contents of register 5 into a memory word. The address of this memory word is determined by taking the sum of
29
7 (R7).
note: Workspace Register 0 (RO) is reserved and may not be specified as an indeg register.
rvIDDIR78eIlNic3
This addressing mode can only be used in the operand fields of "jump" instructions the program counter relative address is written as an expression that corresponds to an address at a word boundary. An Example is the statement:
JMP GETKEY
which jumps unconditionally to location GETKEY. GETKEY is a label that you gave another source statement in the program. It should be noted that when an expression (like GETKEY in the last example) is evaluated it is subtracted from the value of the current location plus two This value is then divided by two with the result being placed in the object code. This value must fall between the values -128 through 127 or the jump will not be executed. This means that the destination of a jump cannot be any farther than 256 (>100) bytes from the current address in the program counter. To sum up you are not allowed to make a jump (using JMP) in your program greater than >100 bytes in length.
DIF*IEF;:iPlirIIDINVe
When programming you will have occasion to add, multiply or otherwise manipulate numbers. The TMS9900 allows addition (+), subtraction (-), multiplication (*), and signed division (/). When an expression is evaluated, the assembler first negates all constants or symbols preceded by a minus (-) sign. All succeeding operations are carried out from left to right. Precedence is only given to the negation of symbols and constants, not to any other procedure. Therefore 4+6/2 is evaluated as 5 and not as 7. A remainder is disregarded in division, thus 5/2+4 equals 6. Parentheses cannot be used to alter the order that an expression is evaluated in.
4t
-
'_2 7
-T- FAI
IINIB
IIIIDINI
EE -T-
The TMS9900 recognizes a number of different instructions. Table 4.1 lists the assembler mnemonic for each instruction and explains what each mnemonic stands for. Also listed is the required operand(s) and operand format for each instruction. You should
30
have a thorough understanding of addressing modes before proceeding to the instruction set. TABLE 4.1 INSTRUCTION SET MNEMONIC A AB ABS AI ANDI B BL BLWP C CB CI CLR COC CZC DEC DECT DIV INC INCT INV LDCR LI LIMI LWPI MOV MOVB MPY NEB ORI RTWP S SB SDO SBZ SETO SLA SOC SOCB SRA SRC SRL DESCRIPTION OPERAND(S) & FORMAT G,(G) G,(G) G (W),# (W),# G G G 8,8 G,G W,# G G,W G,W G G G,W G G G G,#* (W),# # # 8,(6) G,(G) G,(W) G (W),# G,(G) G,(G) CRU CRU G (W),#** G,(G) G,(G) (W),#** (W),#** (W),***
ADD WORDS ADD BYTES TAKES ABSOLUTE VALUE OF OPERAND ADDS AN IMMEDIATE VALUE TO WORKSPACE REG. LOGICAL AND IMMEDIATE VALUE BRANCH BRANCH & LINK BRANCH & LINK WORKSPACE POINTER COMPARE WORDS COMPARE BITS COMPARE IMMEDIATE VALUE CLEAR COMPARE ONES CORRESPONDING COMPARE ZEROS CORRESPONDING DECREMENT DECREMENT BY TWO DIVIDE INCREMENT INCREMENT BY TWO INVERT LOAD CRU LOAD IMMEDIATE VALUE LOAD INTERRUPT MASK WITH IMMEDIATE VALUE LOAD WORKSPACE POINTER W/ IMMEDIATE VALUE MOVE MOVE BYTE MULTIPLY NEGATE LOGICAL OR IMMEDIATE VALUE RETURN WORKSPACE POINTER SUBTRACT SUBTRACT BYTES SET CRU BIT TO ONE SET CRU BIT TO ZERO SET TO ONE SHIFT LEFT ARITHMETIC SET ONES CORRESPONDING SET ONES CORRESPONDING, BYTE SHIFT RIGHT ARITHMETIC SHIFT RIGHT CIRCULAR SHIFT RIGHT LOGICAL
31
* This operand represents the number of bits to be transferred. This value ranges from 0 through 15 with 0 indicating 16 bits. ** This operand is the shift count. ***This operand specifies the extended operation. G - Indicates a general address which can be in one of any of the following modes: a) Workspace Register b) Indirect Workspace Register c) Symbolic Memory d) Indexed Memory Address e) Indirect Workspace Register Auto-Increment W - When this is specified the operand has to be a Workspace Register Address. # - Value entered as a constant. P - This operand is a program counter relative address. CRU - Give CRU bit address. ( ) - The address at which a result is placed when two operands are required.
-7 ,1 ...)
.e.:.
The instruction set can be divided into the following 7 functional groups:
1. 2. 3.
4.
'''' 6. 7.
Data transfer instructions move numbers between registers and memory locations. Table 4.2 outlines the format of each insLruction as well as which bits of the Status Register are affected by each instruction.
TABLE 4.2
Status Register Bits (;) indiGates bits affecLed by instruction MNEMONIC FORMAT
L> A> EQ C OV OP X X X X
-
INT MASK
11N.. - -
X X X
-
X X X
-
A 1-
- - - -
X
-
- -1. - - - -
_ -
1-
_ -
1_
XXXX
- _ _ _ - - -
One of the foundational instructions in assembly language is the "move word" (MOV) instruction. It can transfer a word from a source operand into a destination operand. The destination operand is then compared to zero and sets (or resets) the L>, A>, and ED status bits accordingly. The following are examples of operand combinations that are legal:
*MEMORY TO MEMORY (COPY INTO THERE) *MEMORY TO REGISTER (LOAD REGISTER) *REGISTER TO REGISTER *REGISTER TO MEMORY
Another use of the MOV instruction is to compare a memory location to zero. For example, the following source statements:
move Workspace Register 5 into itself and then compares the contents of R5 to zero. If R5 is equal to zero than the EQ bit is set and the JEQ instruction will cause the program to "jump" to location "CHECK".
1F3
-
IEE.
Et 14fer 'T. ET .
This instruction copies the most significant byte of the source operand into the destination operand.. For example suppose memory location >2E32 contains the value >23A6 and HOLD is located at address >2E32, and if R2 contains >34CC then the statement:
MOVB @HOLD,R2
changes the contents of R2 to >23CC and compares the contents of R2 to zero. As a result of this comparison and the logical greater than, arithmetic greater than, and odd parity bits are set, while the equal status bit is reset.
Places a given number in a specified Workspace Register. The contents of this register is compared with zero and the results of this comparison affect the L>, A>, EQ bits of the Status Register accordingly. For example, the statement: LI R2,>23 *Load Workspace Register 2 with >0023.
loads R2 with >0023 (35) and sets the logical greater than, arithmetic greater than, and resets the equal status bits.
54
IL.WIF" I >
F"
im
Places the Workspace Pointer at the address specified by the immediate operand. For example, the statement: START LWPI >20BA *SET START EQUAL TO >20BA Sets START equal to >20BA and also sets the Workspace Pointer to location >20BA. The LWPI instruction has no effect on the Status Register. Pell I > C3IA:ID, I Kg
01-21...F3 1-:( I rail pi Ern I ir- , A
This instruction loads the interrupt mask of the Status Register (bits 12-15) with a specified value. For example, the statement: LIMI 2 sets the interrupt mask at 2 (>0010) and enables interrupts at levels 0, 1, and 2. While the statement: LIMI 0 disables all interrupts and is the normal state of the computer (>0000).
,
7,0
El;
tE.:3 --r
Lit E3
113
E3 -11-
Stores the current contents of the Status Register in a specified Workspace Register. For example the statement: STST R5 stores the current Status Register contents in Workspace Register 5.
Ft:
WIDIE4i:II<E3F"IPICAE FAD
This instruction saves a copy of the contents of the Workspace Po*nter Register in a specified Workspace Register. For example, the statement: STWP
R4
E3WtqlF"
Y -I FEE];
This instruction switches the most si gnificant byte with the least significant byte in a General Register. In other words, SWPB
? IC ....),)
exchanges the left and right bytes of a specified word. For example, the statement: SWAP SWPB R2 replaces the most significant byte of register 2 (bits 0-7) with a copy of the least significant byte (bits 8-15) contained within the register. Conversely, the least significant byte of register 2 is replaced with a copy of the most significant byte. In this way bytes can be interchanged in anticipation of various byte instructions. In another example, suppose RO contained the value >2244, and memory location >2244 contained the value >FF33, the instruction: SWPB *RO would change the contents of memory location >2244 to >33FF. In summary, the SWPB instruction exchanges left and right (least/most significant bytes) of a word specified in a general register. The SWPB instruction has no effect on the Status Register.
.4.
-4
Arithmetic instructions allow you to perform a variety of arithmetic operations in your program. Table 4.3 shows which bits of the Status Register that are affected by each instruction. TABLE 4.3 ARITHMETIC INSTRUCTIONS
---_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-___
Mnemonic
A
Format
6,(G)
STATUS REGISTER BITS (X) INDICATES BITS AFFECTED BY INSTRUCTION INT MASK L> A> EQ C OV OP X
X X X
AB
ABS AI DEC,
DECT DIV I NC I NCT MPY NEB S GB
G,(G)
G (W),# G
G
- - X X - - - X X X X ^ X X X X X X X X X X - - - X
X X X X X Y._ - 1-- 1-- -
X X
X X X
...-
...-
---
G,(W)
G G G,(W) G G,(G) G,(G)
X X X X X - - - - - Y._ X X X X X - - - - - - - - - X X X - X - - - _ - - ^ X X X X X - - - X X X X X X
36
13 r)
tAi
F: 1.3 E3
This instruction adds a copy of the source operand to a copy of the destination operand and places the sum in the destination operand. For example, the statement: A *R3,*R4+ adds the contents of the word found at the address in R3 to the word found at the address in R4. The sum is placed at the address given in R4 and the address in R4 is incremented by two (Workspace Register auto-increment addressing). The sum is compared to zero and the results of the comparison are reflected in the Status Register. Another example we can look at supposes that the address labeled TABLE contains >2123 and R2 contains >000B, the statement: A R2,@TABLE then causes the contents at TABLE to change to >212E. The logical and arithmetic greater than bits are set and the equal, carry and overflow bits are reset in the Status Register. The contents of R2 remain >000B.
dcb ) E> :E.1 'Ye 11- 1E1 E3
This . instruction adds the left most byte (bits 0-7) of the specified source register to the left most byte of the destination register. The result is placed in the left-most byte of the destination register. For example, in the statement: AB R3,R4 the left byte of R3 is added to the left byte of R4 and the sum is placed in the left byte of R4. Another example, suppose that R2 contained the address >23FA at which was located the memory word >2233, and 'R3 contains >DD8B, then the statement: AB *R2+,R3 changes the contents of R3 to >FF88 and increments R2 by one to >23FB. This result is obtained by taking the left most byte of the memory word specified in the address given in R2 (>22) and summing it with the left most byte in R3 (>DD) coming up with >FF. This sum is then placed in the left most byte of R3 and R2 is incremented to >23FB. Comparison of the sum with zero sets the logical greater then, overflow, and odd parity bits of the Status Register while it resets the arithmetic greater than, equal, and carry status bits. Another example, R4 contains >8100, and
39
The instruction is ignored and the overflow status bit is set while the source and destination operands remain unchanged. Lets take some time now to look at a few examples to see if we can clarify things. Suppose that memory location LOCA contains >0005, R2 contains >0001 and R3 contains >000D, then the statement:
DIV @LOCA,R2
divides 65549 (>0001000D) by 5 and places the quotient 13109 (>3335) in R2 and the remainder, .2 (represented as "2") in R3. In another example suppose that LOCA contains >0002 and R2 contains >0004, also R3 contains a zero, then the statement:
DIV @LOCA,R2
attempts to divide 262144 (00040000) by 2. The resultant quotient, 131072, cannot be represented in a 16-bit word. The result is that the overflow bit is set in the Status Register and the operation is canceled. In summary, the destination operand is a consecutive 2-word area of a Workspace Register. It should be noted that if the destination operand is Workspace Register 15 (R15) the first word of the destination operand is in R15 and the second word is in the memory location immediately following the Workspace area. Note that the DIV instruction does not let you divide by an immediate value directly. To do this, you must put the immediate value into a register a Register or memory location. The following examples illustrates this point.
HERE EQU >14 THERE EQU >05 ZERO EQU >00 MOV MOV MOV DIV @HERE,R7 @THERE,R5 @ZERO,R6 R5,R6
*
* Load equates
*
* Move values into * Computes
20/5,
Another example,
*
* Load Registers
*
* Computes 20/5, result goes in R6.
This instruction increments the source operand by one (1). The result then replaces the source operand. The computer compares the new value to zero and sets/resets the status bits accordingly.
40
With a carry of bit 0, the carry bit is set. With an overflow, the overflow bit is set. An example of the INC instruction is the statement: INC @ADRS which increments the value specified at location ADRS by one. ( I
I INJFe.:1E:FIE .. INUT-
FAN'
1- 104101
This instruction increments the source operand by two (2). The result then replaces the source operand. The computer then compares the sum to zero and sets/resets the status bits accordingly. When there is a carry of bit zero the carry bit is set. With an overflow, the overflow bit is set. Lets consider an example where R3 contains >0022: INCT R3 this statement then increments R3 by two and places the result (>0024) in R3. The arithmetic greater than, logical greater than status bits are set while the equal, carry, and overflow status bits, are reset. Both the increment and the decrement instructions are useful to index byte arrays while the increment and decrement by two instructions are useful to index word arrays.
The MPY instruction performs a multiplication. The source operand is multiplied by the destination operand. The product is then placed in the 2-word destination operand. For example if RO contains the value >0003, R3 contains the value >0005, and R4 contains the value >0EA7, the statement: MPY R0,R3 multiplies the contents of RO and R3 together to get >000F and places this value in R4. R3 now contains a zero (>0000). The Status Register is unaffected by the MPY instruction. Another example supposes that the memory location HERE contains >FFFF and R3 contains >0002, then the statement: MPY @HERE,R3 multiplies the contents HERE (65535) to the contents of R3 (2). The product 131070 (>0001FFFE) is placed into R3 (>0001) and R4 OFFFE). Memory location HERE is unchanged as is the Status Register. If the destination operand is specified as R15 the product is placed into R15 and the first memory word immediately following the workspace memory area.
41
This instruction replaces the source operand with its additive inverse. The computer then compares the result to zero and sets/resets the status bits to reflect this comparison. Suppose memory location VALUE1 contains the value >9BC1, then the statement:
NEB @VALUE1
changes the contents of VALUE1 to >643E. The logical greater than and arithmetic greater than status bits are set in the Status Register while the equal and overflow status bits are reset.
This instruction subtracts a copy of the source operand from a copy of the destination operand and places the result in the destination operand. The result is compared to zero and the status bits are set/reset accordingly. When there is a carry of bit zero, the carry bit is set. When there is an overflow, the overflow bit is set. For example, suppose that memory location HERE contains >2123 and memory location THERE contains >AA33, then the statement:
S @HERE,@THERE
changes the contents of THERE to >8E10 (>AF33->2123). The logical greater than, arithmetic greater than, carry and overflow status bits are set, while the equal status bit is reset.
< 9 Ec )4
This instruction subtracts the source operand, whiLh is a single byte, from the destination operand, which is also a single byte. The difference is then p]aced in the destination operand. The computer compares the resulting byte to zero and sets/resets the Status Register bits to reflect the results of this comparison. When there is a carry of the most significant bit of the byte (bit 0), the carry status bit is set. When there is an overflow, the overflow status bit is set. If the resulting byte has an odd number of bits set to one, then the odd parity bit is set. If the operand is specified in a Workspace Register, then only the left most bits (bits 0-7) are used. For example the statement:
SB RO,R1
which subtracts the left-must byte of RO from the left-most byte of R1, and places the difference in the leftmost byte of Rl. Another example supposes that memory location ADDR contains the value >131D and R5 contains the value >23F5, then the statement:
42
Sb R5,@ADDR changes the contents of R5 to >F610. The logical greater than bit is set, while the other status bits affected by this instruction are reset.
aumF-
EcIF:021rAIGFA
Jump instructions as well as branch instructions are used to transfer control from one area of the program to another. This control transfer may be conditional or nonconditional. These instructions are mainly used to control the sequence in which a program executes. Table 4.4 outlines the conditional and nonconditional branch and jump instructions and the status bits tested by each instruction:
Mnemonic Format
UNCONDITIONAL TRANSFERS
BL BLWP jivIP RTWP .
^ -expression
*X
M.. M.. x
1x
_ -
_ ^ -
_ x
^ _ x
^ - _ _1- - _ - - _
x
x x x
x x
CONDITIONAL TRANSFERS
JEQ JNE JH JL JHE JLE JOT** JLT** JNC JOC JNO JOP expression expression expression expression expression expression expression expression expression expression expression expression t t t t -
t t -
t t t t t t t -
_ _ _ -_ ^ t _ t _ - t -_ r-
^ _ _ -
^ - - _ M.. ^ ^ - - - y- _ _ _ _ ^ - - _ - - - _ _ - _ - -
ITERATION CONTROLS
X XOP ***x source source,operation x x x x x x x x x x
43
* Restores all status bits to the value contained in Workspace Register 15 (R15). ** Only JGT & JLT instructions use signed arithmetic comparisons. All other comparisons are logical (unsigned) comparisons. *** The instruction 'X' does not directly affect any status bits, however the executed instruction affects the Status Register accordingly.
This instruction transfers control to another line in the program. It does this by replacing the contents of the Program Counter Register with the address specified in the operand. This instruction has no affect on the Status Register. For example, if R4 contains >32F1, the statement: B *R4 causes the word at location >32F1 to be placed in the Program Counter Register. This has the effect of letting the word at location >32F1 be used as the next instruction executed by the program. Ec L... lB IA NI IC FI
Nur)
L._ I 104
This instruction transfers control to another line in the program. It also stores the address of the instruction immediately following the BL in RII. The transfer of control is accomplished by replacing the value in the Program Counter Register with the value specified by the source operand. The BL instruction has no affect on the Status Register. For example, if the statement:
BL @SUBL
occurs at memory location >06CA, the instruction places the value >06CE in RII and places memory location SUBL in the Program Counter Register. note: The instruction code which are Therefore, the second word is L.4 F" BL @SUBL requires two words of machine placed at addresses >06CA and >06CC. word address immediately following the >06CE which is the value placed in RII.
IF:
When this instruction is implememnted the following occurs: 1) The source operand is placed in the Workspace Pointer Register.
44
2)
3)
4)
5)
When all operations are finished, the computer transfers control to the new value in the program counter. With the BLWP instruction you can link to subroutines and program modules that do not necessarily share the calling programs workspace.
( ..31"1 F' )
IA PA
0 1.....JI t1/41F-
The JMP instruction allows you to move around in your program. It is similar to the GOTO instruction in BASIC. The JMP instruction causes the computer to take its next instruction from another location. It does not affect the Status Register. It's clean and simple. The following are examples of the JMP instructions usage:
1) 2)
JMP THERE * Jumps to location THERE. JMP >11AF * Jumps to address >11AF.
Keep in mind that when using 'jump' instructions the address you are jumping to has to be within >100 bytes of the address of the jump instruction or the instruction is ignored.
( IR 1- 1AP F" )
FR lc= 1- Li Fiz PA
lAil C) Fc. I< :E.3 F-- IA C:::: lE:-.: F" DI NI 1- IE.. IF: -:"
This instruction serves to return the computer to how things were before the calling of a subroutine through use of a BLWP instruction. Also returns from an interrupt or XOP instruction. The RTWP instruction accomplishes this in the following steps: 1) Replaces the contents of the Workspace Pointer with a copy of R13. Replaces Lhe value in the Program Counter Register with a copy of R14. Replaces the contents of the Status Register with a copy of R15.
2)
3)
In summary, the RTWP instruction restores the execution environment after completion of a BLWP instruction, interrupt, or XOP instruction.
45
There are 12 different instructions that allow your computer to make a "decision" before proceeding along a course of action. These decisions are based on the contents of the Status Register. Some of the conditional jump instructions test to see if the carry (C) bit has been set others test differing combinations of bits. For instance, the instruction Jump on Odd Parity (JOP) jumps only when the Odd Parity (OP) bit is set, others such as the Jump if logical High (JH) only jump if the logical greater than (L>) bit is set to 1 and the equal (EQ) bit is reset to 0. The conditional jump instructions do not change any of the status bits; instead they are the instructions which look at the bits in the Status Register. They are the only instructions which base their activity on Status Register settings. They are the
All conditional transfer "jump" instructions occupy 2 bytes in memory. The first byte holds the operation code, while the second holds the relative displacement. You should always try and construct your programs so that the expected outcome executes when the jump is not taken. Here are a few examples of conditional transfer "jump" instructions:
1)
A R0,R1 * Jumps to location BIG if the add instruction JOC BIG * produces a carry. S R4,R5 * Jumps to location ZERO if the result of this JEQ ZERO * subtraction operation is a O.
2)
You can also check to see if a Register contains a zero by using a MOV instruction, as in the following example:
3)
MOV R4,R4 * Copies the contents of R4 into itself and * compares the result to zero. JEQ ZERO * Jump to location ZERO if EQ bit set.
You can also set up a counter in a program for use in creating delays, loops, arrays, or printing to consecutive screen locations. Counters have the general format:
4)
LI R1,1000 * Put 1000 in R1. DELAY DEC R1 * Decrement R1. MOV R1,R2 * Copy R1 into R1 and compare R1 to O. JNE DELAY * Jump if R1>0 (EQ=0) to DELAY. . * Continue program.
46
expression
is a one or two letter modifier. The expression may be a constant or symbol. Looking at Table 4.5 we see a summary of the conditioina' jump instructions, as well as the conditions that cause a jump to occur. 'jump...if' refers to status bit settings.
where (--)
'Jump if....'
EQ=1 EQ=0 L>=1 L>=0 L>=1 L>=0 A>=1 A>=1 C=0 C=1 OV=0 OP=1
-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_____
The execute instruction allows you to utilize a source operand as an instruction. The X instruction does not alter the Status Register, but the inserted instruction affects status bits normally. If a jump is executed (that is if the status test for a jump is passed) the jump is executed from the location of the X instruction. The X instruction can specify an instruction one, two, or three words in length. Th .-. Program Counter Register is then incremented the required one, two, or three words required by the source operand. The X insLruction is mainly used when the instruction needed is dependent upon a variable factor.
It is very useful to compare various values when computing. That is the purpose of the compare instruction set. Compare instructions have no effect other then to set or reset various status bits. They are used in combination with conditional jump instructions to help the program make decisions. The compare instructions make simultaneous logical and arithmetic comparisons.
47
Arithmetic comparisons compare the two operands as two's compliment values. A logical comparison compares them as unsigned numbers. Table 4.6 outlines a summary of the compare instructions and the status bits each affect:
L> A> EQ C OV OP X
x x x x x x x - x x x - x x -
INT MASK
- - - - - - - - -
( ir )
This instruction compares the source operand, which is a word of memory, with the destination operand which is also a word of memory. The result of this comparison is then reflected by the Status Register. The arithmetic greater than and equal status bits reflect a signed comparison while the logical status bit reflects an unsigned (16 bit) comparison. The operands are left unchanged. The compare instructions act very much like the subtract (S) instruction in that the compare instructions subtract a source operand from a destination operand. The difference is then compared with zero with the Status flags being set accordingly. But unlike the Subtraction instruction, the compare instructions do not save the result; the operands remain unchanged. The sole function of the compare instructions is to set/reset status bits in the Status Register for decision-making by conditional jump instructions. An example of the compare word (C) instruction is the statement:
C RO,R1
which compares RO with R1 (the contents of RO are subtracted from the contents of R1; the difference being compared to zero). The Status Register is then set/reset to reflect the result of the comparison. Table 4.7 gives some examples of the compare words (C) instruction:
48
Source op
-
Destination op
-
>FFFF >7FFF
>s000
>0000 >0000
>0000
0 1 0
0 1 0 0 0 0
0 0 0 1 0 0
The compare bytes instruction is very similar to the compare words instruction we have just covered. The exception is that two bytes are compared instead of two words. For example, the statement:
CB
RO,R1
compares the left byte of RO with the left byte of Rl. The result of this comparison will set or reset the appropriate status bits. The operands are unaffected. In addition to the L>, A>, and EQ status bits, the OP (Odd Parity) status bit is set when the result of the CB operation (really a subtraction operation) contains an odd number of logic one bits. Table 4.8 gives some examples of the use of the CB instruction:
'CB'
instruction
Source op
-
Destination op
-
L>
1 1
A>
0 1
Equal
0 0
Odd Parity
0
>00 >00
>FF >7F
>7F >7F
>80
>BO
>7F >7F
1
0 0
0
0 1
0
1 0
1 1
0
37
AB R4,*R5
then changes the memory word >2232 to .>F492 because >el (the value of the left most byte in R4) plus >11 the (the value in memory byte >2233) equals >92. The left byte in memory word >2232 is unchanged. In this example the logical greater than, overflow, carry and odd parity bits are set, while the arithmetic greater than, and equal bits are reset. dcrEle
e;
This instruction takes the absolute value of an operand. It first checks the sign bit (bit 0) to see if it is equal to on It it is then the two's compliment of the number is taken. If the sign bit is equal to zero, then the number is already positive and the source operand is unchanged. For instance, if RO contains the value >FE00 then the statement: ABS RO changes the value of RO to >0020. In this case when the result is compared to zero, the logical greater than and arithmetic greater than status bits are set, while the overflow, and equal status bits are reset.
Pk I)
Ann I ri
This instruction adds an immediate value to a specified Workspace Register and places the result in the Workspace Register. The sum is then compared with zero and the Status Register bits are set/reset accordingly. For example, the statement: AI
R2,8
adds the value 8 to the contents of R2 and places the result in R2. Another example supposes that R5 contains >0006:
AI R5,>23
the value >0029 is placed in R5. In this case the logical greater than and arithmetic greater than status bits are set, while the equal, carry, and overflow bits are reset.
This instruction decrements the contents of a specified general register (or a memory location specified in the address) by one (1). The result then replaces the source operand. The result is
3e
compared with zero setting/resetting the Status Register accordingly. For example, the statement:
DEC *R4
decrements by one, the word starting at the address given in R4. The DEC instruction is very helpful in counting and indexing of For example, if memory location TABLE contains the byte arrays. value >0001, then the statement: DEC @TABLE places a value of zero in location TABLE (>0000). As a result of this the equal and carry status bits are set, while the logical greater than, and overflow status bits are reset.
( IDEE.C.L'T 3
-1- LN0 C3
This instruction decrements the source operand by two (2). The result then replaces the operand. For example, the statement:
DECT @ADDR1
decrements the contents of ADDR1 by two. The result is compared to zero with the results of this comparison setting or resetting the status bits accordingly. The carry bit is set if there is a carry of bit zero. The DECT instruction is very helpful in counting and indexing word arrays. For instance, suppose memory location TABLE contains the value >2AEO then the statement:
DECT @TABLE
places a value of >2ADE in TABLE. The logical greater than arithmetic greater than and carry status bits are set, while the equal and overflow status bits are reset.
This instruction divides the destination operand (which is a consecutive two (2) word area of a Workspace Register) by a copy of the source operand (one word from a general Register). For example the instruction:
DIV R1,R2
divides the contents of Workspace Registers 2 and 3 by the contents in Workspace Register 1. It should be remembered that when the source operand is greater than the destination operand, normal division occurs. However, if the source operand is less than or equal to the first word in the destination operand, then the quotient will be too large to be represented in a 16 bit word.
49
(I)
4:11MF"AlF.0
Immianiic4m
This instruction compares the contents of a Workspace Register to some immediate value. For example, the statement: CI R3,>21 and the statement: CI R3,33 both compare the contents of R3 with the number 33. The comparison is accomplished in the same manner as with the C instruction. The Status Register bits are set/reset to reflect the results of the comparison.
OC101) ICIE 101"41 C21011 104%.113I104 10
This instruction will set the EQ status bit if the bit positions set to 1 in the destination operand correspond to the bit positions set to one in the source operand. For example, the statement: COC @TEST,R3 compares the logic bits set to 1 in TEST with the bits set to 1 in R3. In another example, suppose MASK contains the word >D012 and R3 contains the value >F693, then the statement: COC @MASK,R3 sets the equal status bit to 1 for we see that: >D012 = 1101 0000 0001 0010 and >F893 = 1111 1000 1001 0011 for each bit set to 1 in the source operand there is a 1 bit in the corresponding bit position of the second operand. If R3 had contained >F890, the equal status bit would have been reset. .ZC:::) ((--
icril
zIEEF.copc _3
icoliFe
cliNinIp4
This instruction will set the EQ status bit if the bits in the source operand that are set to 1 correspond to the bits set to 0 in the destination operand. For example, the statement: COC @MASK,R3 compares the bits set to 1 in MASK, with the bits set to zero (0) in R3. In another example, suppose MASK contains the word >A632, and R3 contains the value >44DF, the above instruction sets the
50
>AB32 = 1010 1011 0011 0010 and >44DF = 0100 0100 1101 1111 1 k \ I
for every logic bit set to 1 (one) in)the source operand (>AB32), there is a logic bit set to (0) zero(In the corresponding bit position of the destination operand (>44DF). However, if R3 had contained the value >44DE the EQ bit would have been reset because:
>AB32 >44DE
= =
1010
1011
0011
0100
0100
1101
in the destination operand (>44DE), in bit position 15 (least significant bit) the bit is not set (not=1). The COC and CZC instructions are used to compare a word with a mask in order to see if either its one bits correspond or its zero bits correspond. To sum up, the COC instruction is used to determine if the word in a Workspace Register has l's that correspond to the l's in a mask that you specify. Conversely, the CZC instruction is used to determine of the word in a Workspace Register has O's in the bit positions indicated by l's in a specified mask.
-411- . -7 IL.... ID 1G I C- itclk ....
L.
Logical instructions are so named because they operate according to the rules of formal logic as opposed to the rules of mathematics. When dealing with logical instructions it is helpful to think in terms of bits set (=1) as "true" and bits reset (=0) as "false." There are ten instructions that allow you to perform various logical operations on memory locations and/or Workspace Registers. These instructions are outlined along with the status bits they affect in Table 4.9.
Mnemonic Format
ANDI ORI XOR INV CLR SETO SOC SOCB SZC SZCB (W),# (W) ,# G,(W) G G G G,(G) G,(G) GOB) G,(G)
x
-
51
( ink Ni r) 1 )
( X COIR )
Logical instructions are primarily used to manipulate the individual bits of an operand. This is opposed to manipulating an entire group of bits as we will learn to do in later sections of this chapter with "shift" instructions. The ANDI instruction utilizes the rule of logic stated:
ANDI R2,>6C4E
then places the value
>2044 in R2 because:
>A3D4 = 1010 0011 1101 0100 ANDed >6C4E = 0100 1100 0100 1110 with this >2044 = 0010 0000 0100 0100 results in this
Notice how if two "set bits" are compared it results in the setting of the corresponding result bit, however, if the bits do not match the corresponding bit is reset. Table 4.10 is a "truth table" which gives the result of all possible combinations of zeros and ones that can be "ANDed" together:
0 1 0 1
0 0 1 I.
0 (T)
0 1
The logical-or immediate (ORI) instruction compares the 16 bit value in a specified Workspace Register with some immediate value. The logical "OR" utilizes a slightly different version of the previously stated logic rule:
Specifically, the 16-bit value in a Workspace Register is compared bit-by-bit (ORed) with some immediate value that you specify. If either of the two bits being compared is "true" (set to 1), then the resulting bit is also true (set=1). This procedure is repeated for each successive bit with the resulting value being finally placed into the Workspace Register. For example, if R3 holds the value >A3D4, then the statement:
ORI R3,>6C4E
places the value >EFDE in R3 because: >A3D4 = 1010 0011 1101 0100 ORed >6C4E = 0 110 1100 0109 .kilp with this >EFDE = 1110 1111 1101 1110 results in this Notice that if either bit being compared is set (=1), then the resultant bit is also set. If neither bit being compared is set, then the resultant bit is reset (=0). Table 4.11 is a 'TRUTH' table listing the result of all possible combinations of bits that can be ORed together.
ORI result
a
1 1 1
The logical exclusive-or [XOR] utilizes the rule of logic which states:
XOR @WORD,R5
exclusive-OR's the contents of memory location WORD with the value in R5. The result of this exclusive-OR operation is then placed in R5. The instruction XOR takes the source operand and
does an
53
exclusive-OR on a bit-by-bit basis with the destination operand. The result of this operation replaces the destination operand. If either of the two bits being compared is "TRUE" (that is =1), but not both, then the resulting bit is also true (set =1). However, if both bits are reset (=0), or both bits are set (=1) then the resulting bit is reset (=0). For example, if R4 contains >A341 and memory location WORD contains >C5F4, then the statement: XOR @WORD,R5 places the value of >66B5 in R5 because: >A341 = 1100 0101 1111 0100 XORed >C5F4 = 1010 0011 0100 pool with this >66B5 = 0110 0110 1011 0101 results in this Notice that if either bit being compared, but not both, is set (=1) then the resulting bit is also set. If neither bit being compared is set then the resulting bit is reset (=0). Table 4.12 is a 'TRUTH" table listing the result of all possible combinations of bits that can be exclusive-ORed together: TABLE 4.12 EXCLUSIVE-OR LOGIC TABLE First Operand Bit 0 1 0 1 Workspace Register Bit 0 0 1 1 XOR Result 0 1 1 0
The value that results from the logical operations ANDI, ORI, and XOR is compared with zero before being placed in the Workspace Register. The results of this comparison then affect the first three bits (L>, A>, EQ) of the Status Register accordingly. For example, if R3 contains >A3D4 then the statement: ORI R3,>6C4E places the value >EFDE in R3, sets the logical greater than bit of the Status Register while resetting the arithmetic greater than and equal status bits. The following chart combines all three 'TRUTH' tables. This chart summarizes the effects of the three logical operations: 0 0 1 1 ANDI AND 0 AND 1 AND 0 AND 1 = = = = 0 0 0 1 0 0 1 1 ORI OR 0 OR 1 OR 0 OR 1 = = = = 0 1 1 1 0 0 1 1 XOR XOR 0 XOR 1 XOR 0 XOR 1 = = = = 0 1 1 0
54
This instruction takes the source operand and reverses all the logic bits. It has the effect of changing each zero in the source operand to one, and changing each one to zero. This is referred to as "taking the one's compliment of a number'. The resulting value is then compared with zero and sets/resets the Status Register accordingly. The new value also replaces the source operand. For example, if R3 contains >3EF4 and memory location >3EF4 contains >A6CC the statement: INV R3 places >C10B in R3 and sets the logical greater than, as well as resetting the equal and arithmetic greater than bits in the Status Register because:
>3EF4 = 0011 1110 1111 0100 becomes >C1OB = 1100 0001 0000 1011 on bit-by-bit reversal
CICIL_Fc)
lEA__ETrAF: wollFcn
This instruction changes the source operand (16 bit) to zero. That is, all bits are reset. For example, if R6 contains >3001 then the statement:
CLR *R6+
clears the contents of memory locations >3000 and >3001 to zero. R6 is then incremented by two (word instruction) so R6 now contains the address >3003. Word operations such as CLR operate on the next lower address when an odd address is specified as the operand, since all memory words have to begin at an even address. The CLR instruction does not affect the Status Register.
cls;E:moo
$3E:T. wicuRn
-rot
DINE:
This instruction is the opposite of CLR in that it replaces the source operand with a full 16-bit word of ones. It does not affect any Status Register bits. For instance, the statement:
SETO
@BUFF(R3)
==
places the value >FFFF at the address found by adding R3 to the contents of BUFF. The SETO instruction is useful to signify the end of a file or in the setting up of flag words. ( EiC)C:: ) E3IEE -11CIIINIFE.:Eis ICIDFRFRF..7.:'.1:31F"CIPAID I 111,4113. . IIAIIIIDIR.:13
This instruction compares two words (16 bits) together. The source operand compares its bits set (1) against the destinaLion operand. All corresponding bits are set in the destination operand regardless of their previous condition. For example, if R3 contains >A3E4 and R4 contains >IC33, then the statement: SOC R3,R4 changes the contents of R4 to >CFF7 because: >A3E4 = >1C33 = >OFF7 = 1010 1001 1011 0011 11 00 1111 1110 11 1111
00
0100 source operand pou destination operand 0111 resulting destination operand
This instruction will set the logical greater than bit of the Status Register and reset the equal and arithmetic greater than bits. Notice that the SOC instruction is really an OR operation that can operate on two operands through any general addressing mode. ( BOIC::1E.c ) BEIT -11CDIONIEE:E; C..":1DIR 1:::-4'. 1E7.. E3 F " C:1 NI ID. :lc IN1C3 ., .
Ery -.11- EI:
This instruction compares the source operand (byte) with the destination operand (byte). It is an OR operation in that if a bit is set in the source operand the corresponding bit is set in the destination operand. The result of this bit-by-bit comparison replaces the destination operand and is then compared with zero. The Status Register bits are set/reset to reflect the results of this comparison. If a word of memory is specified as one of the operands, only the most significant byte (bits 0-7) are OR'ed together. For example, if R3 contains >AA33 and memory location BEST contains >F731, then the instruction: SOCB R3,@BEST places the value >FB31 at location BEST and sets the logical greater than and odd parity status bits while resetting the arithmetic and equal status bits because:
>AA33 =
>FC31 = >FB31 =
0011 source operand 0001 destination operand 000 resulting destination operand
SZC R3,R4
places >2111 in R4 and sets the logical greater than, arithmetic greater than status bits while resetting the equal status bit because:
0010 0001 0011 0011 source operand 0011 0011 1001 1001 destination operand ow gool pogl ppoA resulting destination operand
Notice that if the source operand bit is zero it resets the corresponding destination operand bit. This is a logical OR operation dealing with zeros instead of ones. The opposite of the SOC instruction.
This instruction compares the 0 bits in a source operand (byte) with the 0 bits in a destination operand (byte). If a zero bit corresponds then it is not affected. If a zero bit in the source operand corresponds with a one bit in the destination operand, the destination operand bit is reset to zero. The result of this operation is placed in the destination operand. The resulting binary number from this operation then replaces the destination operand. It is compared with zero and the results of this comparison set/reset the status bits accordingly. For example, if R11 contains the value >2001, location >2001 contains >7D, and location MASK contains >90, then the statement:
SZCB @MASK,*R11
results in the contents of memory location >2001 being changed to >11 and the logical greater than, arithmetic greater than status bits being set while the equal bit being reset because:
MASK = 1001 0000 source operand >7D = 0111 1101 destination operand >11 = 0001 0000 resulting destination operand
57
I NJ E3
"T" 01 Ei;
Where as logical instructions allow you to manipulate individual bits, Shift instructions allow you to manipulate entire groups of bits. There are four instructions that allow you to shift the contents of a Workspace Register one or more bit positions to the left or right. With all four shift instructions the carry status bit (C) holds the value of the last bit shifted out of the register. For example, if a Register is shifted to the right 6 bits, and the sixth bit is a '1', the carry bit in the Status Register is set. Shift instructions can be divided into two groups; Logical shift instructions and arithmetic shift instructions. Logical shift instructions displace an operand without regard for its sign. They are used on unsigned numbers and non-numbers such as masks. Arithmetic shift instructions preserve the sign bit. They are used to operate on sinned numbers. All four shift instructions require two operands; a Workspace Register containing a sixteen bit word and a shift count. The count may be any number from 1 to 16. Table 4.13 outlines the shift instructions and indicates which status bits are affected.
TABLE 4.13 SHIFT INSTRUCTIONS
Status Register Bits (x) indicated bits affected by instruction Mnemonic SRA SLA SRL SRC 9Fc.(-4
IL_ (-4 )
X X X X
13 I-1
X X X X
X X X X
AIR'. IR:
X X X X
X -
I= F.."
L._ IE..
-111-11101
112: :I IC:
These two instructions shift signed numbers. The SRA instruction preserves Lhe sign by replicating the sign bit throughout the shift operation. The SLA instruction on the other hand does not preserve the sign bit, but puts a 1 in the overflow bit of the Status Register if the sign of the number changes after the shift operation. With each bit position shift using SLA, the vacated bit positions are replaced with zeros. When using shift instructions the first operand is the word to be shifted. The second is the number of bits to be shifted (shift count) which ranges anywhere from 1 to 16. If the shift count in
58
the instruction is zero, the shift count is taken from Workspace Register RO; bits 12 through 15. If bits 12 through 15 in RO are all zero then the shift count is 16 bit positions. If a shift count is specified that is greater than 15, then the value is placed in RO and the least significant four bits are taken as the shift count (bits 12-15). If you specify 0 as the shift count the shift count is 16 bit positions. For example, the statement:
SLA R2,4
shifts R2 left four bit positions, if the sign changes the overflow (DV) bit of the Status Register is set. After a shift takes place, the result is compared with zero and the Status Register bits are set/reset to reflect this comparison. The following are examples of arithmetic shift operations: 1. If R3 contains >12F3 then:
SLR R3,1
places a value of >25E6 in R3 and sets the logical greater than and arithmetic greater than status bits while resetting the equal, carry, and overflow status bits because:
>12F3 = 0001 0010 1111 0011 R3 >25E6 = 0010 0101 1110 0110 R3 result (all bits shifted left 1 bit)
n
SLA R4,5
places a value of >62E0 in R4 and sets the logical greater than, carry, and overflow status bits while resetting the equal status bit because:
3.
If R5 contains >6CFD
SLA
R5,0
59
places a value of >F400 in R5 and sets the logical greater than, carry, and overflow bits of the Status Register, while resetting the arithmetic greater than bit because:
>6CFD = 0110 1100 1111 1101 R5 >F400 = 1111 0100 0000 0000 R5 LEFT SHIFT >A BITS.
4. If R6 contains >B690 and RO contains >A3B0 then:
SRA R6,0
places a value of >FFFF in R6 and sets the logical greater than, and carry status bits while resetting the arithmetic greater than and equal status bits because:
>B690 = >FFFF =
1011 1111
0110 1111
1001 1111
(*. B F.:
IF-1 I IF7
This instruction shifts unsigned numbers to the right. The vacated bits are filled with zeros. The carry bit of the Status Register holds the value of the last bit shifted out. The shift count is specified in the same manner as with the SRA and SLA instructions, that is if 0 is specified as the shift count, the shift count is taken from bits 12-15 of RO. If these bits equal 0, then the shift count is 16. The result of the shift is placed in the Workspace Register and compared with zero. The Status Register is set/reset to reflect the results of this comparison. The following are some examples of the SRL instructions usage: 1. If R3 contains >FFFF, then the statement:
SRL R3,6
places the value )03FF in >R3, sets the logical greater than, arithmetic greater than, and carry status bits while resetting the equal status bit because:
1111
1111
1111 R3
SRL R4,456
60
8 because:
R0.= 456 = 0000 0001 1100 1000 ---- last 4 bits = 8 The logical and arithmetic greater than status bits are set, while the equal and carry bits are reset. ir,:".F.,. '.C.-- ) % '
Ei; 1-11 I IF- -11FR I C-3, 1-11 --IF C.: I F-R.' IC Li L._ At IR
SRC R2,6
results in the value >BBE41 being placed in R2. The logical greater than, and carry status bits are set while the equal and arithmetic greater than bits are reset because:
61
* * * *
DIVIDES UNSIGNED NUMBER BY 4. MULTIPLIES AN UNSIGNED NUMBER BY 4. DIVIDES A SIGNED NUMBER BY 4. MULTIPLIES A SIGNED NUMBER BY 4.
These shift procedures can save you considerable program execution time when multiplying or dividing numbers. Each shift operation takes a fraction of the time to complete then does a DIV or MPY instruction. Of course there are limitations, you can only multiply or divide with the shift instructions using multiples of two. You can get around this obstacle by juggling some registers. For example, to multiply the contents of R3 by 10, use the following sequence of instructions:
* * * *
Put a copy of R3 in R4. Shift R4 by 14 (multiply by 4). Add original R4 (multiply by 5). Shift R4 by 15 (multiply by 10).
E(R3*4)+(R3)3*2=R3*10
This instruction sequence involves four steps as opposed to the simple instruction sequence:
LI MPY
R4,10 R3,R4
which only requires two sLeps. However, the former sequence is almost three times faster then the single MPY instruction! 41
-
ic?
---
C: "T. :I tEL1.1
..F.3
As mentioned in earlier sections, pseudo-instructions are not really machine language instructions, but rather provide some direction to the assembler as to what to do under certain circumstances. There are two pseudo-instructions that are outlined below in Table 4.14:
Mnemonic NOP RT
62
The NOP pseudo-instruction performs no operation when run. It only serves to slow the execution time of the program. No operands are specified and the Status Register is unaffected. The NOP pseudo-instruction is most often used with the minipemory assembler to allow you to leave "holes" in your code that you may want to come back later and fill with some additional instructions.
This instruction tells your computer to return back to a calling program from a subroutine called up by a BL instruction. For example, the instruction sequence:
line# >0001
Label MAIN
>0200
@SUB1
>0201
START
* Branch to location SUB1 and store * Return address of next * Instruction in R11.
>0800 >0E105
SUB1 .
RT
branches to location SUBP, carries out a sequence of instructions and then returns via the RT to the point just after the BL instruction (in this case we would return to location START). When the RT instruction is specified the assembler supplies the logic code for the following:
B *R11
Remember that when control is transferred by a BL instruction, the link to the calling routine (the Program Counter setting just after the BL instruction) is placed in R11. The RT pseudoinstruction returns control of the program to the instruction following the BL command. Do not alter R11 unless you first_ save the address somewhere. Do not forget to reload the address in Rll before RT or there is no telling where you will end up!
1.
Construction an instruction sequence that will multiply a number by 12 using only shift instructions. Where is the return address stored when a BL (Branch & Link) instruction is called? How far can a "jump" be specified in your program? The sole purpose of the Status Register is to provide information on which decisions are based to what group of instructions? What pseudo-instruction is used in combination with the BL instruction? Identify the addressing mode used in each of the following examples: (a) (b) MOVB R1,*R2 A *R1+,R2 (c) C @OA,@VALUE1 (d) MOV R6,@NUM1+S(R2)
2.
3. 4.
5.
6.
5 ASSEMBLER DIRECTIVES
As we have mentioned before, the purpose of the assembler is to convert your source code into the appropriate object code. That is, the assembler program takes your opcodes and their operands, translates them into the appropriate binary numbers, and places them in memory for you. This is the assembly process in its simplest form. By providing some additional commands you can "teach" the assembler program to assist you in creating your assembly program. This is where Assembler Directives come in. They are not part of the computers instruction set. They are directions for the assembler to follow during the assembly process. Sometimes they are referred to as "pseudo-instructions" as are NOP & RT, but for now we will put them in a distinct category and refer to them separatly as assembler directives. There are 28 separate directives that are available, however with the assebler and loader we are using only 22 directives are useful. These will be the ones that we will discuss. The directives can be divided into 5 separate groups based on their functional similarities.
-65-
66
ASSEMBLER DIRECTIVES
The assembler directives can be divided into the following 5 functional groups:
1.
These directives affect the location counter in some way. The location counter is the pointer that determines where the assembler is in the assembly process. It keeps an orderly flow of where data and/or instructions are stored in the memory.
2.
INITIALIZE CONSTANT DIRECTIVES. These directives let you define symbols. It allows you to assign a symbolic name to an expression. You can also directly define words & bytes. PROGRAM LINKAGE DIRECTIVES.
These directives allow you to link different assembly program modules together into one long program. This feature can greatly simplify program development. These directives allow you to define extended operations. They also allow you to define the end of your program.
3.
4.
MISCELLANEOUS DIRECTIVES.
5.
These directives allow you to change the assembler output in order to make it easier to read, such as page lengths, page titles, program idenLifiers, ect.
is the pointer that determines where the assembler stores instructions or data in memory. It sequentially follows the steps in the source listing as it converts it into the object listing. There are 6 useful directives for altering the location counter.
Directive
. .
Format
---------------------------
Absolute ORiOin Relocatahle ORiGin Dummy ORiGin Block Starting with Symbol Block Ending with Symbol Move to a Word Boundary
-------------------------------------------------------
67
When the assembler reaches a AORG directive, the location counter is altered to store the object code for subsequent instructions starting at the location specified by a word. For example if X=7, then the source code statement:
LABEL AORG
>D000+X
sets the location counter to >D007, and LABEL is assigned the value >D007. With the Editor/Assembler you normally let the computer make the placement decisions but AORG gives you the option of making these decisions yourself. When using the Line-by-Line Assembler with the Mini Memory Module you will use the AORG directive quite frequently to move through various memory locations. See chapter 10 section 10.1 for further details. (F;:01FR 10) -
IFZIEFIVE: DIRIBINI
You may locate object code relative to the current active storage location in memory. The RORG places a value in the location counter which, if encountered in absolute code, also defines succeeding locations as program re-locatable. The dollar sign ($) symbol refers to the current value of the location counter. The statement:
LABEL RORG $ 40
-
overlays the last 20 words (40 bytes) by backing up the location counter 20 words. LABEL is assigned the value that is placed in the location counter. You may never have occasion to use AORG and RORG in your own programs (provided you are not using the MMM), but you'll encounter them if you ever delve into listings of system programs. For this reason you should know what AORG and RORG do. (13101FZIGi)
DUMM'Y DIF;cIBINI
This direct:lye places a value in the location counter and defines the following address locations as a dummy block or section. (F4E39) Eci_DCZA< CIF'
F3IFIPIII
The BSS directive allows you to reserve an area of memory for future use. If a Label is used it is assigned the location of the first byte in the block. it does this by advancing the location
68
ASSEMBLER DIRECTIVES
counter by the value specified in the expression. You reserve memory for use to set up reference tables, arrays, ect. The following code reserves a 32 byte area of memory for your 16 Workspace Registers:
MYREG BSS
32
If the AOR5 directive is to be used in your program, it must precede come before you use any BSS directives.
(EKE3)
muEriciwy
EEtNinir4c3 8 .ymEcc3L__
NM
This directive is similar to that of the BSS directive in that it reserves a block of memory by advancing the location counter by the value specified in the expression. The label is assigned the location of the last byte in the block. For example, if the location counter contains ';-2n0 when the assembler processes the statement:
BUFF BES
>30
BUFF is assigned the value >230 and a 48 byte area of memory is reserved. The BES directive can be used to mark the end of a block started with the BSS directive. For example, when the assembler processes the statements:
icE.T.vrEiNto
lorA
wcwzr>
..ocluNinemR-sy
All words in memory begin at an even address. EVEN is a directive that can force the location counter to point to an even address. If the location counter is already at an even address then the directive is ignored, but if the counter is at an odd address, EVEN causes the assembler to jump to the next even address. For example, if the location counter points to address >3001, an EVEN directive makes it point to >3002. The only time you wou)d need to use the EVEN directive would be to ensure that a statement consisting of only a label is at an in word boundary after a TEXT or BYTE directive.
ASSEMBLER DIRECTIVES
69
You do not need to use an EVEN directive instruction or a DATA directive because the automatically advances the location counter when it processes machine instructions or a
You can avoid much of the hassle of having to use the EVEN directive by simply not specifying a statement consisting of only a label after a TEXT or BYTE directive.
These directives allow you to define the values of constants and place the values in bytes or words of memory. Table 5.1 outlines the directives that initialize constants along with their mnemonics and formats:
Directive
Define assembly-time constant (EQUate) Initialize BYTE Initialize WORD Initialize TEXT
Format
expression exp,exp...exp exp,exp...exp 'string'
IC IE. D. 1.11 3
I:3 Faib.
f 1. ini ea.
f= 4=11
This directive assigns a value to some symbol. The label field contains the symbol that you assign. Once you assign the symbol you may use it anywhere you would normally use the expression. The EQU directive can be used to define a symbol for a 16-bit constant, or another symbolic name. Some examples of the EQU are:
JOYX UP
You can also specify an index reference through some juggling of the EQU directive like so:
>8300 * My own workspace area begins here. MYREG+2 * Value in high byte of R1 addr. >8302. MYREG+3 * Value in low byte of R1 addr. >8303.
Here we see the individual bytes of a Workspace Register reference through the use of a symbolic equate directive.
70
This directive can place one or more values in successive bytes of memory. When you specify a label it is assigned the location which the first byte is places at. Each expression is evaluated individually as a signed two's compliment 8-bit number. The following statements show the allowable maximum and minimum values for byte-size variables, in decimal:
* Maximum byte constant, unsigned. BUMAX BYTE 255 * Maximum byte constant, signed. BSMAX BYTE 127 BSMIN BYTE -128 * Minimum byte constant, signed.
You can also allow the assembler to calculate the value of a constant as in the following example:
1, 34+>12,>10/8,'A'
-
which initialize five bytes of memory starting with the byte at location HERE. The contents of five successive bytes are >13, >FF, >F0, >02, and >41. The EVEN directive is often used after the BYTE directive when a DATA or TEXT directive is next in the source code. This is to assure that the next directive begins at an even word boundary.
11 4:11)
I AIL_ I Z. EE
011R. 13
This directive only differs from the BYTE directive in that it can place one or more successive values in 16-bit word locations. Each word is evaluated as a signed two's compliment 16-bit number and, if necessary, places a value of >00 in any bytes not filled. The followed statements outline the maximum and minimum values for word-size variables, in decimal:
WUMAX DATA 65535 * Maximum word constant, unsigned. WSMAX DATA 32767 * Maximum word constant, signed. WSMIN DATA -32768 * Maximum word constant, signed.
Again, it is possible to let the assembler calculate some of the values of the constant as in the following example:
HERE DATA
1+>F3,3121+ C,'AB'
which initialize three words of memory beginning at location HERE. The conLents of the three successive words are >00F4, >F01, 4142. The BYTE and DATA directives can be used to set up in memory. To do this simply list the table elements them with a comma. The following sequences of source two 20-element tables, one comprised of bytes and Lhe a data table and separate code set up other
ASSEMBLER DIRECTIVES
71
comprised of words:
SOUND1 EQU BTABLE BYTE BYTE BYTE SOUND2 EQU WTABLE DATA DATA DATA
(BYTE TABLE)
The text directive allows you to define a character string as an expression. The string characters are stored in successive bytes of memory as their ASCII hexadecimal egivalents. The string may be up to 52 characters in length. You may precede the string with a urinary minus (-) sign in which case the last character of the string is negated. When a label is used its location is the first byte in the string. The string must be enclosed in single quotes as shown here with two possible error messages outlined:
NICE TEXT THAT NUMBER IS TOO LARGE. TEXT 'PLEASE RE-ENTER IT.' RUDE TEXT 'TRY IT AGAIN, STUPID'
The bytes are filled sequentially by the assembler when processing a TEXT directive. So if 4_he assembler is on an even address when it starts to execute the following directive,
it_ I PA F.::
ff.:4
1E3 IEEE
".%)1
ET: 1:7-1
Program linkage directives allow you to Lreate programs as separate modules which you later connect together to form one long program. There are a total of five directives that are available to allow you to link programs, however, only three of them can be used with the loader provided with the assembler. These will be the ones we will discuss in depth in the sections that follow.
72
ASSEMBLER DIRECTIVES
Table 5.2 outlines the directives that allow you to link programs along with their mnemonics and required formats: TABLE 5.2 DIRECTIVES THAT LINK PROGRAMS Mnemonic DEF '
REF
Directive
External DEFinition External REFerence
Format
symbol,symbol symbol,symbol symbol symbol
Copy
Copy
"File Name"
<
la X 7- EE F: IPA IA
:11.)
NI I *T"
The DEF directive allows you to makes one or more symbols available to other programs for reference. The DEF directive can be thought of as supplying "entry" points into the program for other programs. The DEF directive must precede the object code that contains the symbols to be defined. For this reason the DEF directive is usually at the beginning of the source code. The following statement shows an example of the usage of the DEF directive:
11=7
E: X 11" E.7 F:
The REF directive allows you to have access to one or more symbols defined in other programs. The REF gives you the location of where "entry" into another program is to take place. For instance, the statement:
ASSEMBLER DIRECTIVES
73
separate source file in the assembly process as if it were a series of source statements in the program. The assembler continues right on through. You can use as many COPY directives in a program as you want but if an END directive is encountered the assembly process ends. This happens no matter if the END directive is in the file called up or part of the original program. The following statement is an example of the COPY directives use: LABEL COPY "DSK1.8AME1" COPY "DSK1.GAME2" COPY "DSK2.GAME3" END This last example will first copy the file GAME1 from disk drive 1 into the computer in order for the assembler to assemble it. It then loads file GAME2 from disk drive one and keeps right on assembling it. Finally, file GAME3 is loaded from disk drive two and it is assembled. The assembler then reaches the END directive and the assembly process stops. The main use of the COPY directive is to allow you to write programs as separate modules which can then be assembled together. You may want to do this for writing convenience or because the source program is too long to fit on one file.
:r
IS, '
ID I. Fir.1E:C::11-
'1/4./1E:E3
The two miscellaneous directives are the Define eXtended Operation directive (XOP) and the END directive. The miscellaneous directives are outlined in Table 5.3 below: TABLE 5.3 MISCELLANEOUS DIRECTIVES Mnemonic Directive Format
XOF Define extended OPeration symbol,term END Program END symbol -, -----------------------------------------------------------------C X DP* EE F.:" I NI FE EL: X -11- t1/44 F.) 1E: t,"- 1E: IR. onh I- (3 INJ
This directive can only be utilized on the TI-99/4A Home Computer. The DXOP directive will assign a symbol to be used in the operator field to specify an extended operation.
!NJ 11:3 )
ET. X
The END directive causes the assembly proce s s to stop. The last source statement you put into your program should be an END statement to signify to the assembler that this is her you want the program to end. lf you specify a label it is assigned the current value in the location counter.
74
ASSEMBLER DIRECTIVES
You can specify and entry point into the program by placing a symbol in the operand field of an END directive. If this is done the program will automatically begin running as soon as it is loaded into the computer. For example, the statement:
END START
will cause the program to begin running immediately upon loading starting at address START. If an operand is not specified in the END directive, then you must define the entry point with a DEF directive and type in this entry point in response to the 'PROGRAM NAME' prompt you receive after loading the program using the Editor/Assembler. If you are using the Line-by-Line Assembler with the Mini Memory Module to program in assembly language the END directive will cause you to exit the assembler. See chapter 10 for more detailed information.
Directive
DoNot List Source List Source PAGe Eject page TITLE program IDenTifier
Format
'string' 'string'
CIL_I9.-T3 L_IE3 -T
4 SCAJII , BIEDUF
These directives have no effect on the assembler unless you have specified a listing to an output device with the L option of the Editor/Assembler. If you have specified a list file option then the UNL directive will halt the output to the file device such as list file or printer. The UNL directive in not printed out and any source statements following it are not printed.
ASSEMBLER DIRECTIVES
75
The LIST directive may be used after a UNL directive to resume printing to an output device such as a list file or printer. The list statement is not printed, but the location counter is incremented and the listing begins with the next source statement. To summarize the UNL and LIST directives are used to stop and start output by the assembler to a list file device such as a disk drive or printer.
( FIPkeiE:: >
F" int IS
This directive causes the assembler to start printing the source listing (provided the L option has been selected) on a new page. If a label is specified it is assigned the current value of the location counter.
The TITL directive will print a heading (provided the L option has been selected) on each subsequent page of the source listing. For example, the statement:
( I :DT- >
The IDT directive assigns a name to the program. It is printed in the source listing but serves no other purpose during the assembly process. The name is limited to 8 characters in length after which a "TRUNCATION" error is displayed. If a label in specified it is assigned the value of the current location counter.
76
ASSEMBLER DIRECTIVES
40,R3 R6 R3 OUT
3. Write some statements (two lines should suffice) that will store the contents of R3 into a word location called SAVE. 4. What does this instruction do?
MPY >23FF
UTILITY PROGRAMS
In your computer there exists two distinct areas of random access memory (RAM). The first is termed CPU RAM (Central Processing Unit RAM) and is readily manipulated by you. The second is VDP RAM (Video Display Processor RAM) and is more difficult to manipulate because it is memory mapped. When you are putting something on the screen, describing sprites, or writing to the sound table you are actually writing to the VDP RAM. Normally it would be difficult to read and write to the VDP RAM areas because in order to read data you would first have to write a value to a specific address, wait while the data is obtained and then read the data from another address. To write data to VDP RAM the opposite process occurs, namely you place the data in a specific address, write a value to another address to signify that the date is to be written, and then wait while the data is written. This requires an in-depth knowledge of the addresses to use, as well as how to use them. Fortunately, you have ready access to certain utility programs that allow you to write and read easily to and from the VDP RAM. The following is a listing of utility programs available to you. All utility programs needed by your program must be referenced in a REF statement at the beginning of the source code unless you are using the Mini Memory Module with the line-by-line assembler in which case you should refer to chapter 10.
-77-
78
UTILITY PROGRAMS
Table 6.0 outlines the utility programs that are available to you along with a description as to what they do:
TABLE 6.1 UTILITY PROGRAMS Symbol VSBW. VMBW VSBR VMBR VWTR KSCAN GPLLINK DSRLNK XMLLNK Name
VDP Single Byte Write VDP Multiple Byte Write VDP Single Byte Read VDP Multiple Byte Read Write to VDP Register Keyboard SCAN Graphics Programming Language Link. Device Service Routine Link Extended Memory Language Link
Description
Copies a single byte from CPU RAM into VDP RAM. Copies Multiple bytes from CPU RAM into VDP RAM. Copies a single byte from VDP RAM into CPU RAM. Copies multiple bytes from VDP RAM into CPU RAM. Copies a single byte from CPU RAM into a VDP register. Scans the keyboard and joystick for input and returns it. Links your program to Graphic subroutines that you can use. Links your program to peripheral devices. Links your assembly program to ROM and RAM routines.
vipp.
Ervir
This utility allows you to place a single byte in VDP RAM. You place the VDP RAM address you want to write to in RO. You place a copy of the byte you want to write in the most significant byte of Rl. You then call the utility. For example, to place >05 at VDP RAM address >0040, you would use the following source code:
UTILITY PROGRAMS
79
civr-ma44)
NoPIDIF-
mulL_ -riF
Eiv -ria
WFCITE
This utility program allows you to copy any number of bytes from an area of CPU RAM into an area of VDP RAM. The Block Starting with Symbol (BSS) instruction is usually used to reserve the CPU RAM to hold bytes prior to transfer. To use the VMBW utility, place the VDP RAM address you wish to start writing to in RO. Place the starting address of the information in CPU RAM that you wish to copy in Rl. R2 is then loaded with the number of bytes to copy. The utility program is then called. For example, the following source code:
copies the 32 bytes located in BUFFER into VDP RAM starting at VDP address >0300.
E4V -Tla
Fdapkup
This utility allows you to copy a single byte from an address in VDP RAM into CPU RAM. You do this by placing the VDP address you want a copy of in RO. Then when the utility is called, the value at that address is placed in the most significant byte of Rl. For example, if VDP address >0300 contains the value >FF, then the following statements:
IRlischn
This utility allows you to copy any number of successive bytes from VDP RAM into CPU RAM. Load RO with the starting address in VDP RAM that you want to start copying from. Load R1 with the CPU address that you want to copy into. You load R2 with the number of bytes to be copied. You then call the VMBR utility.
BO
UTILITY PROGRAMS
For example, if you want to copy 40 bytes from VDP RAM beginning at address >0780 into CPU RAM beginning at address BUFFER, you would use the following source code: REF VMBW BUFFER ;SS >28 . LI LI LI BLWP RO,>0780 R1,@BUFFER R2,>28 @VMBW
(vtArriR) wiFicure..
This utility allows you to change the contents of the VDP Workspace Registers. You place the value you want the VDP register to be in the least-significant byte of RO. The most significant byte of RO is loaded with the VDP register you want to change. For example, the code: REF VWTR
. RO,>02CE LI BLWP @VWTR places a value of >CE in VDP register 2. NOTE: When changing VDP register 1, place a copy of what you are changing it to at CPU RAM address >83D4. You have to do this because the value at this address is loaded into VDP register R1 when a key is pressed after the screen has "blacked-out" which it does if no key is pressed for a long period of time.
(KirAIA) KlavnipAIRD
(4&./
This utility allows you to check the keyboard and joysticks for input. It also returns the ASCII value of the key that was pressed or the position of a specified joystick. On the next page is Table 6.2 which presents the CPU RAM addresses used by the KSCAN routine.
UTILITY PROGRAMS
81
>8376
>8377 >837C
If your program contains a keyboard scanning loop and your program needs to enable interrupts (to move sprites, create sound, ect.) the key scanning loop is an excellent place to do so. The following is an example of how to structure the key scanning loop so that interrupts may be enabled:
* Reference needed utility program. * Enable interrupts * Disable interrupts * Call utility program to scan keyboard.
A keyboard status byte is located at CPU address >837C. It gives certain status information based on keyboard input. It can be used in combination with a compare ones corresponding (COG) instruction to determine if a key has been pressed. Bit 2 of the status byte is set if a pressed key is detected during execution of the KSCAN utility. The following source listing on the next page can be used to detect a pressed key.
82
UTILITY PROGRAMS
REF
KSCAN
>2000 >837C
* Binary 0010 * * * * * *
0000
0000
0000.
Call up utility program. Move status word into R3. Check and see if bit 2 is set. If no key pressed loop again.
An alternative method of checking to see if a key has been pressed is to check address >8375 to see if it contains the value >FF (no key pressed). The following source code performs this check:
REF
KSCAN
KEY HEXFF
EQU BYTE
>8375
>FF
GETKEY
BLWP
CB JEQ
@KSCAN OHEXFF,OKEY * See if a key was pressed. GETKEY * If no key pressed, check again.
( OR'L_L_INK: ) (3PcicbF"1-1 I C3
e U G
C) t3
r-1 Ni I 184 io
L. I IN tc::
The following GPL routines can be used by your program to perform some useful tasks such as loading character sets, producing tones, allocating string space ect. All the GPL routines are accessed through GPLLNK. The GPL routines covered in the following sections return to your program after they have finished executing. In order for you to use the GPLLNK utility you must include the statement REF GPLLNK in your program source code. You must also set the status byte located at address >837C equal to >00 before branching to GPLLNK. The address of the desired GPL routine is put in a DATA statement immediately following the BLWP @GPLLNK instruction. The source code on the following page illustrates these points.
UTILITY PROGRAMS
83
* Reference GPLLNK routine. * * * * R1=0 Set Status Register byte=0 Call utility. Designate routine desired.
Table 6.3 lists all the subroutines available with the GPLLNK utility.
TABLE 6.3 GPLLNK UTILITY ROUTINES Data >0016 >0018 >0020 >0034 >0036 >0038 >003B >003D >004A Description
Loads the standard character set into VDP RAM. Loads small capitals character set into VDP RAM. Executes the "power up" routine. Generates the "accept tone". Generates the "bad response tone". Executes the "get string space" routine. Bit reversal routine. Cassette device service routine. Loads lower case character set into VDP RAM.
The following are complete descriptions of each GPLLNK routine that is available.
REF LI MOV
Reference needed utility. Beginning address to load characters. Place beginning address at >834A. R1=0 Move 0 into >837C. Call up utility. Designate subroutine desired.
84
UTILITY PROGRAMS
DATA >0020 EXECUTE POWER-UP ROUTINE It returns you to the This GPL routine initializes the system. master title screen, clears the VDP circuits and places the default values in the VDP registers, character set, status block, and Color Table. Available VDP RAM size is stored at >8370. DATA >0034 GENERATE ACCEPT TONE
This routine causes a tone to be generated. It is the same tone that is generated in BASIC in association with a correct input.
UTILITY PROGRAMS
85
DATA >003D CASSETTE DSR ROUTINE This routine allows you to access a cassette recorder. In order for this routine to work a number of condition must be met: 1. The Peripheral Access Block (PAB) and data buffer must be set up in VDP RAM prior to calling the routine. The screen start address must be >00 for prompts issued by the cassette DSR (Device Service Routine).
2.
3. Address >834A is the beginning of the device name (ie. "CS1"). 4. Address >8356 points to the first character following the name in PAB. Address >8354 and >8355 are the length of the device name (ie. >0003 for "CS1"). The word at address >83D0 should be set to
>0000.
5.
6. 7.
Address >836D must be set to >08 to indicate a DSR call. The status byte at CPU address >837C must be set to >00.
8.
DATA >004A LOAD LOWER CASE CHARACTER SET This routine is only available on the TI-99/4A. This routine allows you to load the lower-case character set into a designated area of VDP RAM. Before calling this routine, load CPU RAM address >834A with the starting address in VDP RAM that you want to begin loading the characters. ( ID B IRIL... Ni F.< )
Er N.," I IC 8 la Ft V I IC E.: Fc rol
urr 1 r4 la
This utility allows you to link your assembly language programs with peripheral devices such as printers, disk drives, cassette recorders, ect. It also allows you to link to a subprogram in ROM. Before calling this utility a number of conditions must be set up: 1. A Peripheral Access Block (PAB) must be set up in VDP RAM to describe the characteristics of the device and file to be accessed. The word at CPU RAM address >8356 must be loaded with the value that represents the device or subprogram name length.
2.
86
UTILITY PROGRAMS 3. A DATA directive after the BLWP @DSRLNK is >8 for
linkage to a Device Service Routine and >10 for linkage to a ROM routine.
If after the DSRLNK utility is called and no error has occurred, bit (EQ) of the Status Register is reset. If however, and Input/Output error has occurred, the equal bit is set and the error code is stored in the most-significant bit of RO of the calling programs workspace. Appendix F outlines the Input/Output error codes. NOTE: You can not use this routine to access a cassette because the cassette Device Service Routine is located in GPL GROM and not normal DSR ROM. In order to access a cassette you must use the statement:
BLWP @GPPLNK DATA >003D fS .. 1 (IF* Pli Et ) IF*EFeli I F'a I-I la IR A IL__ Pil IC B B
PABs are used by Device Service Routines to access peripheral devices. The structure and format of a PAB is the same for every peripheral. You must place the necessary information describing the peripheral device into the PAB before attempting to open the file. The PAB is made up of 10 more bytes which provide information to the DSR Utilities regarding the characteristics of the peripheral device and file attributes that you want to access. Table 6.4 describes the bytes that make up the PAB as well as a description of the information each contains:
Description
I/0 code describing current file condition. See following sections for complete description of all allowable I/0 codes.
-Status Byte-
This byte contains all the information the computer needs to describe the file. It includes information regarding file type, data type, and operation mode. The contents of each bit is outlined below:
87
Contains
Error Code
Description
When an error is detected during an operation the error code is returned here. '00' indicates that no error has been detected. The error codes are further outlined in Table 6.6
Record Style
Place a value of '0' for "Fixed length records" and a value of 'I' for "Variable length records".
Data Format
Place a value of '0' for "DISPLAY" and '1' for "INTERNAL". "UPDATE"='00', "OUTPUT"='01' "INPUT"='10', "APPEND"-'11' Load '0' for "Sequential Files" and '1' for "Relative Files".
5-6
'") 4-
*tr
.....
All Data Buffer This is the address in VDP RAM that you want to put data read from a Address record or where you place data that you want to write to a record. All Record Length The length of each record for "fixed length records" or the value of the maximum length of a "variable length record". This byte contains the number of characters that you want to WRITE onto a record or it contains the number of characters that is to be READ from a record. This byte is only used with "relative It gives the current record files". number that the next I/O operation is
All
Character Count
6-7
ALL
RECORD #
88
UTILITY PROGRAMS
8 All
Screen Offset
This byte contains the offset of the screen characters with respect to their normal ASCII values. This is only used with a cassette interface, which requires prompts to be placed on the screen. This byte contains the length of the File Descriptor begins at byte 10.
9 All
Name Length
10 All
Device/File Contains the device name and if necessary, Descriptor the file name. The length of this description is given in byte 9.
For%Js ImFqirr'olurrFq_rr
caiDiB
The following are complete descriptions of each Input/Output code that can be used in Byte 0 of the PAB:
DIFNEM
>00
Before you can do anything with a file or device you must open it. The only exceptions to this are the SAVE and LOAD operations. You cannot alter byte 1 (STATUS BYTE) when an OPEN operation has been performed, the file remains open until a CLOSE operation takes place. If byte 4 of PAB is set to >0000 (Record Length), the record length that is specified by the attached peripheral is returned in byte 4. If the value for the record length is given by you is greater than 0, then it is used only after being checked against the peripheral in question.
ICILADBE
>01
This operation will close a previously opened file. If the file was originally opened in APPEND or OUTPUT mode, an END OF FILE (EOF) record is written to the device or file before closing occurs. After a file is closed you can alter byte 2 (STATUS BYTE) to
UTILITY PROGRAMS
89
change to a new mode of operation before going through the next OPEN operation.
Ft E AD
>C:1
This operation will READ a selected record from a designated peripheral device. The obtained information is stored in VDP RAM beginning at the address specified in bytes 2 & 3 (Data Buffer Address) of the PAB. The size of the buffer is number of bytes stored is given in byte 5 (Character Count) of PAB. When a READ operation takes place, if the length of the inputted record exceeds the buffer size, the remaining bytes are discarded.
11,4 Ft I ir E
>07,5
This operation will write to a record from the buffer specified in PAB bytes 2 & 3. The number of bytes that will be written is given in byte 5 of the PAB.
> c) A-
This operation will reposition the file pointer to the beginning of the file for sequential files. If the file is a relative file, the pointer is set to the record specified in bytes 6 & 7 of PAB. The RESTORE/REWIND operation can only be carried out if the file was opened in UPDATE or INPUT mode. You can simulate a RESTORE operation when you are using relative files by entering the record at which the file is to be positioned in bytes 6 & 7 (Record #) of the PAB. This will then be the next record accessed in the next operation.
L...1010;13
>on
This operation code will allow you to load the memory image of a file from a peripheral into an area of VDP RAM. You are allowed to use LOAD without a previous OPEN operation. The following information must be placed in the PAB before instituting a LOAD operation: 1. 2. Place >05 in byte 0 of PAB. Place the starting address in VDP RAM that you want the file to be copied into in bytes 2 & 3 (Data Buffer Address) of the PAB. Place the maximum number of bytes to be loaded in bytes 6 & 7 (Record #) of the PAB. Place the name length in byte 9 of the PAB. Place the file descriptor information in bytes 10 on.
3. 4. 5.
90
UTILITY PROGRAMS
Keep in mind that the LOAD operation will require as much memory space in VDP RAM as the file occupied on a diskette or other medium.
This operation code will allow you to write a copy of a file in VDP RAM to a peripheral. You are allowed to use SAVE without a previous OPEN operation. The following information must be placed in the PAB before instituting a SAVE operation.
1. Place >06 in byte 0 of PAB. 2. Place the starting address in VDP RAM from which the file is to be copied in bytes 2 & 3 (Data Buffer Address) of the PAB. Place the number of bytes to be saved in bytes 6 & 7 (Record #) of the PAB. Place the name length in byte 9 of the PAB. Place the file descriptor information starting in byte 10 of PAB.
3. 4. 5.
This operation code will delete the file specified from the peripheral. A CLOSE operation will then be performed.
13 a L_ E 'T. E: IR a
lc oi Fc o
> ci a
This operation code will remove a specified record from a relative record file. The number of records that you want to delete is placed in bytes 6 & 7 (Record #) of the PAB. If this operation code is specified with files opened as sequential, an error occurs.
When the operation code is specified certain status information is returned regarding the peripheral device and file. The status information returned is placed in byte 8 (Screen Offset) of the PAB. Bits 0 through 5 have meaning whether the file is opened or closed, bits 6 & 7 only have meaning when the file is open; otherwise they are reset.
UTILITY PROGRAMS
91
Table 6.5 outlines bits of byte 8 (Screen Offset) and the information regarding status that each returns:
Status Information
If this bit is set (=1), the file does not exist. If this bit is reset (=0), the file does exist. With devices such as printers this bit would never be set because any file can conceivably exist. The file is write-protected if this bit is set. If resei, this file is not protected and can be written to. Reserved, Always reset. If this bit is set it indicates that the Data Format is INTERNAL. If this bit is reset it indicates that the Data Format is DISPLAY or that the file is a program file. If this bit is set it indicates that the file is a program file. If this bit is reset it indicates that the file is a data file. If this bit is set it indicates that the record length is VARIABLE. If this bit is reset it indicates that the record length is FIXED. If this bit is set, the file is at the actual physical end of the peripheral and no more data can be written. If this bit is set, the file is at the end of its previously entered data. You can write more data to the file but if you attempt to read past this point an error will be generated.,
2 3
5 ,.)
0000 0000
0000 0100
92
UTILITY PROGRAMS
Bytes 2 & 3 would indicate the address in VDP RAM where we will place the data that we will later input to the file. In this case we will put it starting at address >1000 like so:
0001 00000
0000
0000
0101 0000
0000
0000
Bytes 6 & 7 are only used with relative files so we will reset them both to 0 like so:
0000
Byte 8 is our screen offset for a cassette inteface which we are not using, so we reset it to o like so:
000 0 0000
The remaining bytes, 10 and on, contain the Device and File Description. Since these are given as ASCII values we will use a TEXT directive to enter it
TEXT
'DSK1.FILE1'
UTILITY PROGRAMS TABLE 6.6 FILE ACCESS ERROR CODES Error code Bits Meaning
0 1 .. 2 000 001 010
93
...) 3
011
4 5
100 101
6 7
110 111
Bad device name. Device is write protected. Incorrect file type, incorrect record length, incorrect I/0 mode, no records in a relative file. Illegal operation; a operation that is not supported on the peripheral or a conflict with the OPEN attribute. Out of Buffer space on the device. You have attempted to read past the end of the file. The file is closed when this error occurs. Device error, bad medium and other hardware problems. File error such as data/program file mismatch, non-existent file opened in INPUT mode ect.
NOTE: An error code of 0 indicates that no error has occurred. unless bit 2 of the status byte at address >837C is set. If bit two is set in the Status Register it indicates a bad device name. Your program should check bits 0 through 1 of byte 1 of the PAB after every I/O operation to see if an error has occurred. You should also clear these bits before every I/O operation. There are some default values that the DSR will use if no values are specified. The following chart outlines these defaults. DEFAULT CONDITIONS 1. 2. 3. 4. 5. SEQUENTIAL UPDATE DISPLAY FIXED if relative records, VARIABLE if sequential Record length depends on the peripheral
You also need to construct a PAB in order to comunicate with RS232 interfaces. The following source code illustrates how you may output information to a printer or other peripheral attached via a RS232 interface:
000 001
002 * 003 MYREG
004 *
94
UTILITY PROGRAMS
005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053
EQU EQU EQU BYTE BYTE DATA BYTE BYTE DATA BYTE BYTE TEXT
* * * * * * * * *
TEXT 'ERROR DETECTE D= ' TEXT '0123456789ABC DEF' LWPI MYREG MOV R11,R10 BLWP @KSCAN MOVB @STATUS,R0 JEQ LOOP LI LI LI BLWP LI LI LI BLWP BL LI BLWP BL LI BLWP BL JMP LI MOV BLWP DATA JEO RT RO,>0002 R1,MESS R2,34 @VMBW RO,PAB R1,>0300 R2,>29 @VMBW @STEP4 R1,>0300 @VSBW @STEP4 R1,>0100 @VSBW @STEP4 LOOP R3,PAB+9 R3,@PNTR @DSRLNK 8 ERROR
* STEP1
* STEP2
* * Write PAB data to * VDP RAM * * Open file * * * Write to file * * * Close file * * Set * PAB ponter * * * *
* STEPS
* STEP4
UTILITY PROGRAMS
95
054 055 056 057 058 059 060 061 062 063 064 065 066 067 068
ERROR
* Error handling routine * * * Get error number * * Print * error * number * and * message * on screen
* MESS *
96
UTILITY PROGRAMS
1. Write a short program that will place the value 34 at VDP RAM address >1000.
j..) .4... al
If CPU RAM address >8375 contains >FF after calling the KSCAN utility, what does that indicate?
3. Write a short program that will select the keyboard device that checks input from the left side of the keyboard and joystick #1.
7 GRAPHICS
Your TI home computer is a versatile machine in that it can construct colorful graphics in a virtual infinite number of different shapes. There are four basic screen modes you can use to aid you in constructing graphics, they are as follows:
1.
GRAPHICS MODE
-97-
98
There are a total of 8 VDP registers labeled 0 through 7. Each register contains a single byte. You can change the contents of a VDP register by using the VWTR utility. The VDP registers contain information that determines how the computer displays graphics on the screen. The following is an example of using the VWTR utility to put a value of >01 in VDP register 7:
REF
VWTR
* Reference needed utility program. * VDP R7/value to load=>01 * Call utility program
The following is a brief description of each VDP register. The default values (values loaded in when the computer is turned on) are also listed:
%/nip IFcez
c)
The default for VDP Register 0 is >00 for BASIC, xBASIC, and Editor Assembler. The following table outlines what each of the bits in VDP Register 0 controls.
0 - 5 These bits are reserved. All these bits must be reset (=000000). 6 If this bit is set, the screen is put in
BIT-MAP MODE.
7 External video enable/disable. Setting this bit enables video input and resetting this bit disables video input.
vnif.,
FIS;MIR
The default for VDP Register 1 is >E0 for BASIC, xBASIC, and Editor Assembler. A copy of VDP Register 1 is located at CPU RAM address >83D4. If no key has been pressed for a long time the computer automatically "blanks" the screen. When subsequently a key is
99
pressed, the computer reloads VDP register 1 with a copy of what is in address >83D4. Therefore if you want to change VDP register 1, make sure you put a copy of its new value at address >83D4. Table 7.1 outlines what the bits in VDP Register TABLE 7.1 VDP REGISTER 1 BITS Bit 0 Description Selects 4K or 16K RAM operation. A value of 0 selects 4K RAM operation, and a value of 1 selects 16K RAM operation. Blank enable/disable. Setting this bit (=1) causes the screen to go blank. Resetting this bit (=0) causes the screen to display normally. When the screen is blanked, only the border color remains on it. Interrupt enable/disable. Setting this bit (=1) enables VDP interrupt and a resetting this bit (=0) disables VDP interrupts. If this bit is set, the display is in TEXT MODE. If this bit is set, the display is in MULTICOLOR MODE. Reserved, must be O.
Sprite size selection. Resetting this bit (=0) selects for standard sized sprites. Setting this bit (=1) selects double-sized sprites. Sprite magnification selection. Setting this bit (=1) selects magnified sprites, and resetting this bit selects unmagnified sprites. 1 controls.
3 4 = ,i 6
e 1110
0000
VDP registers 2 through 6 define the beginnings of the Screen Image Table, Color Table, Pattern Descriptor Table, Sprite Attribute Table, and Sprite Descriptor Table. We will discuss each of these tables in great depth in subsequent chapters. But for now it is a good idea not to alter these registers from their default values.
100
:..... -,
The default for this register is >00 in BASIC, XBASIC and Editor Assembler. This register defines where the Screen Image Table begins The beginning of the Screen Image Table is found by multiplying the value in this register by >400.
The default value for this register is >0C in BASIC and >20 in xBASIC.
>0E
in Editor/Assembler,
This register defines the beginning of the Color Table. The beginning address is found by multiplying the value in this register by >40.
ika ID F. Fr 1E: G I 1- PC
1.. 31
The default value for this register is >06 in the Editor/Assembler, BASIC and xBASIC. This register defines the beginning of the Sprite Attribute Table. The beginning address is found by multiplying the contents of this register times >80.
ivinF.
Fze I B -raF
e)
The default value for this register is >00 in the Editor/Assembler BASIC and xBASIC. This register defines the beginning of the Sprite Description Table. The beginning address is found by multiplying the contents of this register times >800.
The default value for this register is and >17 in BASIC and xBASIC.
>F5
in the Editor/Assembler
101
Table 7.2 lists the bits in VDP Register 7 and what each controls:
The following table summarizes the most important bits in the various VDP registers. These are the bits that you should become familiar with, as a working knowledge of them is necessary in order to program properly. TABLE 7.3 SUMMARY OF IMPORTANT VDP REGISTER BITS VDP Register RO R1 R1
R1 R1
Bit 6* 3* 4*
6 7
Controls
If set, set, If set, If set, If set,
If
is in BIT-MAP MODE. is in TEXT MODE. is in MULTICOLOR MODE. are double-sized. are magnified.
ri C31).
GRAPHICS MODE is the mode you probably will be programming in most of the time. It allows you to use the standard ASCII characters and define patterns of your own to display on the screen. You can also define the foreground and background colors for any characters. The ASCII character patterns are available to you. You can use sprites and set them in motion in graphics mode. Graphics consist of characters. Each character is made up by a
102
on the screen you want the character to be displayed. There are three separate tables that contain the information needed to produce graphics on the screen. The three tables and the information they contain are as follows:
1. 2.
PATTERN DESCRIPTOR TABLE Holds character pattern identifier a) COLOR TABLE a) Holds color code for foreground and background color of character SCREEN IMAGE TABLE a) Refers to the screen location of the pattern.
3.
To sum up, graphics are created by setting up information about their shape, color and screen location in the tables. It is recommended that your three graphics tables start at the following VDP RAM addresses (These are the VDP Register default values):
>o3eo
>0000
The Pattern Descriptor Table can hold up to 256 different patterns or characters. Each character is defined by a "pattern identifier" as outlined in your User's Reference Guide. Each pattern takes up 8 bytes in the Pattern Descriptor Table. Thus character 0 takes up addresses >0800 through >0807, character 1 takes up addresses >0808 through >080F, and character 256 occupies addresses >OFFS through >OFFF. In GRAPHICS MODE the standard ASCII character patterns are automatically loaded into the Pattern Descriptor Table by the system. So character 32 (space character) occupies bytes >0900 through >0907, and ASCII character 33 (exclamation point) occupies addresses >0908 through >090F and so on with the other ASCII characters. To find the Table address for any character simply multiply its character number times 8 and add it to >0800. For example to find the table address that starts defining ASCII character 65 (Capital letter 'A'):
E (65) * (8)
103
If you want to add additional character patterns of your own but do not want to alter any of the ASCII character patterns already present you can place your own character patterns beginning with character number 128 and extending through 256. Of course, you can alter any pattern in the Pattern Descriptor Table, if you wish.
icolLADIFc
iripluit__
The Color Table codes for the foreground and background color of each character. Each color code takes up one byte in the Color Table. Each byte codes for the foreground and background color of eight successive characters. The four most-significant bits code for the foreground color and the four least significant bits code for the background color. The Color Table begins at VDP RAM addresses >0380. The following are the values for the 16 colors available on the TI Home Computer. Note that the values are somewhat different in assembly language then they are in BASIC:
BITS SET
0000 0001 0010 0011
0100
COLOR
Light yellow Light red Dark yellow Light yellow Dark green Magneta Gray White
CODE
>8 >9 >A >B >C >D >E >F
BITS SET
1000
1001 1010
The byte at address >0380 specifies the colors for characters 0 through 7, the byte at address >0381 specifies the colors for characters El through 15, and the byte at address >039F specifies the color of characters 248 through 255. For example, if we place a value of >F1 at VDP address >0384, characters 32 through 39 are displayed as white on black.
ICIIRIEIN4 IMIAB
TiPirE
In the BASIC language the screen is divided into 24 rows of 32 columns. A screen location is designated by a row and column number. For example the statement:
CALL HCHAR(4,5,65,1)
will place the capital letter 'A' in the 4th column row 5.
104
The computer has no concept of a "screen"; it just views the screen as a series of memory locations. There are no rows and no columns, only 768 possible memory locations numbered 000 through 767. These memory locations begin at VDP address >0000 and extend through address >02FF. These addresses make up the Screen Image
Table. Figure 7.6 shows how the consecutive memory locations designate the consecutive screen locations:
032 064 .
O N
033 965 .
0
034 066 .
a
. . .
g
IV
a
V II * *
O a
a a
a 736
" a a
P a
//I N * "
767
If you place the ASCII value of a character in the Screen Image Table, the character will appear in the designated place on the screen. For example, if you place the value 65 in VDP RAM address >23 then the character 'A' will appear in screen position 035. To convert a row and column location into a Screen Image Table address simply use the -Following -Formula: C C + (R * 32) 3 =P where C is the column number, R is the row number, and P is the
resulting Screen Image Table address. Now that we know how graphics are put together we can construct a small assembly language program to illustrate how it all goes together. Consider the BASIC program:
10 20 30
This short program prints character 65, which is the "A" character, on the screen at row 4 column 10. The character is printed white on a black background. To convert this to an assembly language program we have to load the needed information into the proper tables as demonstrated on the next page.
GRAPHICS MADE EASY 001 002 003 * 004 MYREG 005 * 006 START 007 * 008 009 010 * 011 012 013 014 015 * 016 HERE 017 DEF REF BSS LWPI LI LI BLWP LI LI BLWP JMP END START VSBW >20 MYREG R0,>0384 R1,>1F00 @VSBW R0,138 R1,>4100 @VSBW HERE START * Define program entry point. * Reference needed utilities.
105
* Reserve memory for my registers. * Pointer to beginning of my workspace. * Color Table address. * Byte to write (white on black). * * Screen Image Table address. * Load character 'A' ASCII 65. * Character is displayed in screen position 138. * This holds display on screen. * Program runs when loaded.
Now suppose we want to define a character of our own. In BASIC we would add a CALL CHAR statement to our previous program. We will now define a ball pattern as character 128 and color it red. We will then display it on the screen:
10 20 30 40
To translate we simply add some additional code to load the new pattern into the Pattern Descriptor Table, and change the color values in the Color Table:
001 002 003 * 004 MYREG 005 BALL * 006 007 START 009 010 011 012 * 013 014 015 016 017 * 018 019 020 021 HERE 022
DEF REF BSS DATA LWPI LI LI BLWP LI LI LI BLWP LI LI BLWP JMP END
START VSBW,VMBW
>20 >3C7E,>FFFF,>FFFF,>7E3C MYREG RO,>0390 R1,>8000 @VSBW RO,>0C00 R1,BALL R2,8 @VMBW R0,138 R1,>8000 @VSBW HERE START
* Pattern
* Pointer to beginning. * Load * Color Table (red) * * Load ball * pattern into * Pattern Descriptor Table * * * * * * Screen position Character (ball) to write. Place ball on screen. Hold it on screen. Program runs when loaded
106
MULTICOLOR MODE
divides the screen into a series of "boxes". Each box is a 4 x 4 pixels in size. You can define the color of each individual box. There are 64 boxes in a row and there are a total of 48 rows. You are not allowed to define characters or use ASCII characters when in MULTICOLOR MODE. You are allowed to use sprites in MULTICOLOR mode. To place the screen VDP register 1.
in MULTICOLOR MODE you must set bit 4 in
You must place the following values when using MULTICOLOR MODE: TABLE 7.7
VDP ADDRESSES
>0000 >0020 >0040 >0060 >0080 >00A0 >0000 >00F0 >0100 >0120 >0140 >0160 TO TO TO TO TO TO TO TO TO TO TO TO >001F >003F >005F >007F >009F >00BF >00DF >00FF >011F >013F >015F >017F
VDP ADDRESSES
>oleo TO >019F
>01A0 >01C0 >01E0 >0200 >0220 >0240 >0260 TO TO TO TO TO TO TO >02e0 TO >02A0 TO >02C0 TO >02E0 TO >01BF >01DF >01FF >021F >023F >025F >027F >029F >02BF >02DF >02FF
VALUES TO LOAD
>60 >60 >60 >60 >BO >BO TO TO TO TO TO TO TO TO TO TO TO TO >7F >7F >7F >7F >9F >9F >9F >9F >BF >BF >BF >BF
>eo
>80 >A0 >AO >AO >AO
Once you have loaded the Screen Image Table with the above values you can start describing the colors of the boxes on the screen. This is done by placing values in the Pattern Descriptor Table. The Pattern Descriptor Table thus describes colors in MULTICOLOR MODE instead of patterns as it did in GRAPHICS MODE.
The Pattern Descriptor Table should begin at address >0800 in VDP RAM. The first byte in the Pattern Descriptor Table describes the color of the first two adjacent boxes on the first row. The color codes are given on page 103. The left four bits of the byte describe the color of the first box and the right four bits describe the next box on the same row.
The next byte in the table defines the colors of the first two boxes in the second row. The third byte describes the first two boxes in the third row. This continues until the first two boxes
107
in all 48 rows have been defined. Thus, the first eight bytes in the Pattern Descriptor Table describe the color of the first two columns of boxes. The second group of eight bytes in the table define the colors of the third and fourth columns of boxes. This continues until the last eight bytes in the Pattern Descriptor Table are reached OODF8 to >ODFF) which in their turn define the colors of the last two columns of boxes.
-
7__.. s
mx -117- mania
rows. You are not pixels in size. of 768. Thus the often used in
In TEXT MODE the screen is 40 columns by 24 allowed to use sprites. Each character is 6 x 8 There are 960 possible screen positions instead Screen Image Table is longer. TEXT MODE is most word processing programs.
To place the screen in TEXT MODE you must set bit 3 in VDP register 1. Two colors are available in TEXT MODE, the pixels that are turned off are the color defined in bits 4 through 7 of VDP register 7. The bits that are turned on are the color defined in bits 0 through 3 of VDP register 7. The tables used in TEXT MODE are set up the same way as the Screen Image Table and Pattern Descriptor Tables are in GRAPHICS MODE except that the Screen Image Table is longer, and in the Pattern Descriptor Table the last two bits of each entry are ignored because each character is only 6 x 8 pixels instead of 8 x 8 pixels as they are in GRAPHICS MODE.
-
BIT-MAP MODE is available only on the TI-99/4A Home computer due to its use of an advanced microprocessor chip. BIT-MAP MODE allows you to define independently each of the 768 screen positions. You can also independently set the color of each pixel in a character. You can use sprites in BIT-MAP MODE but you cannot move them using automatic motion. In BIT-MAP MODE the Pattern Identifier Codes are stored in the Pattern Descriptor Table. The color codes that describe the colors of these patterns are stored in the Color Table. The Screen Image Table contains the number referencing a given pattern from the Pattern Descriptor Table. The reference numbers range from >00 to >FF each referencing a successive pattern in the Pattern Descriptor Table. In BIT-MAP MODE you should start the Screen Image Table at VDP RAM address >1800. You do this by setting VDP Register 2 equal to >06. Add the following code to your program to accomplish this: LI BLWP RO,>0206 @VWTR * (SEE PAGE 80 FOR A REVIEW * OF THIS UTILITY)
108
The Pattern Descriptor Table begins at VDP RAM address >0000 and is >1800 bytes long. In order to start the table at address >0000 you must load VDP Register 2 with >00 as in the last example. Each pattern identifier code (pattern) takes up 8 bytes in the Pattern Descriptor Table, thus there are 768 possible patterns. See your User's Reference Guide, subprogram CHAR, for further discussion of pattern identifier codes. The Color Table should begin at VDP RAM address >2000. You can do this by loading a value of >04 into VDP Register 3. The Color Table is >1800 bytes long. Each color code is 8 bytes long. The color codes are described on page 103. The first four bits of each byte code for the color of the pixels that are 'on' in one row of 8 pixels, and the last four bits of each byte code for the color of the pixels that are 'off' in the same row of 8 pixels. For example, the pattern identifier for our ball, "3C7EFFE7E7FF7E3C," which starts at address >0000 of the Pattern Descriptor Table would have >00 as its reference code. You can display the ball anywhere on the screen by entering its reference code in the appropriate place of the Screen Image Table. Other patterns in the table are referenced in the same way. For example, the second group of 8 bytes in the Pattern Descriptor Table (second pattern) are referred to in reference code >01 and so on for all other patterns. The 8 bytes in the Color Table beginning at address >2000 hold the color codes for the ball, the next 8 bytes code for the colors of the next pattern and so on. Now lets look at an example to illustrate these last points. Say we want the ball to be red with a black background. We also want the ball to have a white square in its center. Our ball pattern would be constructed as follows:
HEX CODE
1 1 lx1x1x1x1 1 1
lx1x1x1x1x1x1 1 lx1x1x1x1x1x1x1x1 lx1x1x1 ', lx1x1x1 lx1x1x1 1 lx1x1x1 lx1x1x1x1x1x1x1x1 1 lx1x1x1x1x1x1 : 1 1 lx1x1x1x1 1
>3C
The following code would load this pattern into the Pattern Descriptor Table beginning at VDP address >0000. Don't forget to change the value of VDP Register 4 to >00 first. .
PATTAB EOU >0000 PAT DATA >3C7E,>FFFF,>FFFF,>3C7E . LI RO,PATTAB LI R1,PAT LI R2,8 BLWP @VMBW
GRAPHICS MADE EASY Now that the pattern is loaded we need to define its colors. First lets draw a map outlinning the colors we want. Black=8, Red=R, and White=W: COLOR CODE
109
*Each row of 8 pixels is coded for *with one byte. The first 4 bits *code for the pixels that are 'ON' *in the row, in this case the code *i s red (8). The second group of *bits code for the color of pixels *that are 'OFF' in the row, in *this case black (1) or white (F).
We can use the following code to load these values into the Color Table beginning at address >2000. Remember to load VDP
Register 3 with >04 prior to reaching this segment:
COLTAB EQU >2000 COLORS DATA >8181,>818F,>8F81,>8181 LI R0,COLTAB LI R1,COLORS LI R2,8 BLWP @VMBW
When programming there will be instances when you will want to change which pixels are 'on' and which pixels are 'off' in a character. To do this it will be necessary to calculate the byte and bit position that needs to be changed in the Pattern Descriptor Table. You may also on occasion wish to change the foreground and background colors of a group of eight pixels. To do this it will be necessary to calculate the byte in the Color Table that should be changed.
If you know the X-position and Y-position of a pixel, you can use the following source code to calculate the bit offset and byte that refers to the pixel in the Pattern Descriptor Table. This source listing also provides the byte to change in the Color Table. See page 115 for a description of how how to determine pixel X and Y coordinates.
110
In this example RO contains the X--position and R1 contains the Y--position of the pixel: .
MOV R1,R6 SLA R6,5 SOC R1,R6 ANDI R6,65287 MOV RO,R7 ANDI R7,7 RO,R6 A R7,R6 S
R6 is the address in the Pattern Descriptor Table that you must change. R7 is the bit that must be altered. The address of the Color Table byte that you will need to change is found by adding >2000 to R6. The following source code segment can be used to alter the VDP Register values so that the Pattern Descriptor Table, Screen Image Table and the Color Table all begin at the proper addresses required for BIT-MAP MODE: . LI
RO,2 * Put screen @VWTR * in BIT-MAP MODE. R0,>0206 * Screen Image Table @VWTR * begins at address >1800 R0,>0403 * Pattern Descriptor Table @VWTR * begins at address >0000 RO,>03FF * Color Table @VWTR * begins at address >2000
This next source code segment can be used to initialize the Screen Image Table. The values >00 through >FF are loaded three times in succession:
* * * * * When FF+1 is reached, (>00) * no jump is made * * Repeat loading >00 to >FF * three times
111
This final segment can be used to initialize the Color Table. Here we will color all pixels that are "on" black and all pixels that are "off" white. We do this by loading successive values of >F1 into the Color Table: . . LI RO,>2000 R1,>F100 LI LOOP BLWP @VSBW INC RO RO,>3801 CI JNE LOOP
. .
The following subprograms illustrate how BIT-MAP MODE can be used. Subprogram INITBM will initialize all tables and place the screen in BIT-MAP MODE. Subprogram TURNON will 'turn-on' a single pixel whose X and Y coordinates have been placed into R3 and R4 respectively. If you are using the Editor/Assembler, you need not type in these subroutines directly into your program. This is because they are all DEF'd. All you need to do is include the subprogram names in a REF statement in your program and follow these steps: 1. Type in the subroutine coding for INITBM and TURNON and save it to disk. Assemble it into an object file named BITMAP. Write your own program which places the X and Y location of the pixel you want to turn-on in R3 and R4 respectively. Include in your program a REF INITBM,TURNON statement. Assemble your program into a file named DEMO (or whatever). Select the LOAD & RUN option and when prompted for the file name type DSK1.DEMO and press ENTER. When prompted for the next file name type DSK1.BITMAP and press ENTER. Press ENTER again. When prompted for a program name, type START and press enter. Program should now execute.
2.
3.
4. 5.
6. 7.
If you are using the Line-by-Line assembler you will have to type in the source code as part of every program that uses BIT-MAP MODE.
112
This program will draw a rectangle when given the two points of one of its diagonals. 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 DEF REF * HIGHX HIGHY LOWX LOWY * START * EQU EQU EQU EQU BLWP LI LI BLWP DEC CI JNE LI INC CI JNE LIMI JMP END START INITBM,TURNON 65 50 50 150 @INIT R3,HIGHX R4,HIGHY @TURNON R3 R3,LOWX PLOT R3,HIGHX R4 R4,LOWY PLOT 2 $ * Diagonal * end * points * * Initialize & enter BIT-MAP MODE
PLOT
The following are the INITBM and TURNON routines: 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 DEF REF * MYREG INITBM BSS DATA LI BLWP LI BLWP LI BLWP LI BLWP LI CLR LI BLWP INC AI JNE INITBM,TURNON VWTR,VSBW >20 MYREG,$+2 R0,2 @VWTR RO,>0206 @VWTR RO,>0403 @VWTR RO,>03FF @VWTR RO,>1800 R1 R2,3 @VSBW RO R10100 LOOP
* Enter BIT-MAP MODE * Screen Image Table = >1800 * Pattern Descrp. Table = >0000 * Color Table = >2000
LOOP
113
022 023 024 025 026 027 028 029 030 031 032 033 034 035 036
037
CLR DEC JNE * LI LI BLWP INC CI JNE LI CLR BLWP DEC JNE RTWP DATA MOV MOV MOV ANDI SZC SLA A MOV ANDI S A SWPB MOVB SWPB MOVB NOP MOVB SOCB ORI SWPB MOVB SWPB MOVB NOP MOVB RTWP DATA END
LOOP1
* R1 @VSBW RO LOOP2
LOOP2
038 039 * 049 TURNON 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 GET 077
MYREG,$+2 @6(R13),R3 @8(R13),R4 R4,R5 R5,7 R5,R4 R4,R5 R5,R4 R3,R0 RO,>FFF8 RO,R3 R4,R0 RO RO,@>8CO2 RO RO,@>8CO2 @>8808,R1 @GET(R3),R1 RO,>4000 RO RO,@>8CO2 RO RO,@>8CO2 R1,@>8C00 >8040,>2010,>0804,>0001
114
1.
Write a few lines of source code that could be used to put the screen in MULTICOLOR MODE. Write a few lines of source code that could be used to display sprites as double-sized and magnified. What will the following source code statements do?
2.
3.
REF
VWTR
5. 6.
-115-
116
In your computer there are three different tables that collectively contain all the information needed to define sprites. You simply load the desired information into the tables and change it as needed to redefine the characteristics of your sprites. The three tables and the information they contain are as follows:
2. SPRITE DESCRIPTOR TABLE a) b) Sprite pattern identifier Specify magnified or double-sized sprites
As mentioned before you can have up to 32 separates sprites completely defined and operating at one time. These sprites are numbered from 0 (first sprite) to 31 (last sprite). Before we discuss the three sprite tables in greater detail we must first understand how the computer defines the screen for sprites. For sprites the computer divides the screen into a series of rows and columns. The columns are labeled starting on the left from 0 to 256 (>00 to >BE). The rows are numbered somewhat differently, starting from the top left, the first row is numbered 256 (>100), followed by the numbers 0 through 255 (>00 to >FF). Each screen location defined by a row and column in this manner is referred to as a pixel. A pixel is the smallest area of the screen that can be turned on or off. Most of the time you
117
will probably enter the sprite screen position as hexadecimal values, so table 8.1 outlines the rows and columns of all pixel locations in HEX code:
TABLE 8.1 ROW AND COLUMN PIXEL LOCATIONS PIXEL COLUMN . . >00 >01 >02 .
>100 1 >00 1 . . p1 . . .
. .
.
p2 I
II
. .
IP II IX 1E IL 1R 10 IW
>01
.
.
.
.
p3
.
>02 1
.
II
>BB >BD
I 1
. . .
. . p4 . .
>BE I
Looking at Table 8.2 it can be seen that pixel p1 is in row >100 and column 02, p2 is in row >100 column >FF, p3 is in row >01 column 02, and p4 is in row >BE column >01. There are some formulas available for converting a graphic row and column location into pixel locations and vice-versa. These formulas are as follows:
118
8- 0 B P- FicI M
TintEcLE
You should begin the Sprite Attribute Table at VDP address >0300. The Sprite Attribute Table holds the information regarding the present screen position of all sprites as well as their colors. The entries in the Sprite Attribute Table change constantly as the position of moving sprites changes. There are 32 possible sprites numbered 0 through 31. Each sprite takes up four bytes in the Sprite Attribute Table. The first byte is the row or "Y" position of the sprite. The second byte is the column or "X" position of the sprite. The (Y) position starts with >FF then continues with >00, >01, >02 and so on until >BE. The (X) position extends from >00 through >FF. The third byte references the pattern of the sprite as to where it is located in the Sprite Descriptor Table. It can contain any value from >00 to >FF. The fourth byte is the early clock attribute and also codes for the color of the sprite. When your computer moves sprites it updates the entries in the Sprite Attribute Table. The more sprites it has to update the longer it takes to execute the program. To shorten the time and increase program efficiency you can place a value of >DO as the Ylocation of the lowest numbered non-moving sprite in the Sprite Attribute Table. This indicates that all subsequent sprites are undefined. For example, if you have 10 sprites in motion you should place a value of >DO at address >0328. If you have no sprites defined, you should place a value of >DO at address >0300. To sum up, it is recommended that you always let the final unused sprite be undefined by specifying a Y-location of >DO. The third byte references a pattern in the Sprite Descriptor Table. The pattern reference number can range from >00 to >FF. The value of this byte corresponds to a character defined in the Sprite Descriptor Table. For example, if the third byte contained a value of >80 it would represent the character defined by address >0400 through >0407 in the Sprite Descriptor Table. The fourth byte controls the early clock of the sprite and its color. The four most significant bits (bits 1-4) control the early clock. If the last bit (bit 4) is reset to zero the early clock is off and the location of the sprite is said to be its upper left-hand corner. This means that the sprite will fade in and out on the right hand side of the screen. If the fourth bit is set to one the early clock is on and the sprites location is shifted 32 pixels to the left. The sprite can then fade in and out on the left side of the screen. The color of the sprite is determined by the contents of the four least significant bits of the fourth byte in the Sprite Attribute Table. The values are given on the next page.
119
TABLE 8.3 COLOR CODES COLOR Transparent Black Medium green Light green Dark blue Light blue Dark red Cyan CODE BITS SET
s.1 IT Ul 42, At..,1II"'0
COLOR Medium red Light red Dark yellow Light yellow Dark green Magenta Gray White
CODE
8 9 A B C D E F
BITS SET 1000 1001 1010 1011 1100 1101 1110 1111
0000 0001 00 10
0011
010 0 0101
0110 0111
You should take note that the color codes differ slightly in assembly language from their counterparts in BASIC.
The following diagram illustrates how an entry into the Sprite Attribute Table might be constructed. Two sprites are specified. Sprite 0
Sprite 1
'RIR I11- EE
n la is
IFt I Fm -TC:11Fc
-TAtEsi_la
The Sprite Descriptor Table describes the patterns of sprites in the same way that the Pattern Descriptor Table describes characters. You will usually begin the Sprite Descriptor Table at address >0400. You can start it at a lower address, but these are usually reserved for the Screen Image Table, Color Table, and Sprite Attribute List. Addresses >0400 through >0407 are defined as sprite pattern >80, sprite pattern >81 occupies addresses >0480 through >040F and so on through sprite pattern >EF which occupies addresses >0778 through >077F.
You can make sprites magnified double-sized or both by writing a value to the two least significant bits of VDP register 1. Table 8.4 which begins on the next page, explains the different sizes and magnifications possible as well as the correct values to write to VDP Register 1.
/20
01
10
11
8-:.22
SF>IFCITIa MOITIDINJ
-T- 04
The Sprite Motion Table specifies the X and Y velocity of each sprite. The Sprite Motion Table begins at address >0780. Before a sprite can be put into motion, several conditions must be met. The first thing that must occur is that your program must allow interrupts. You can enable interrupts with the LIMI 2 instruction however, before your program accesses VDP RAM you will have to disable the interrupts with a LIMI 0 instruction in order that the interrupt handling routine does not alter the VDP write address. You must also indicate in your program how many sprites will be in motion. This is done by placing a value at address >837A in CPU memory. For example if sprites 2, 5, and 7 are in motion, the number 8 be put in address >837A in order to allow motion of sprites 0, 1, 2, 3, 4, 5, 6, and 7.
121
A description of the motion of each sprite must be placed in the Sprite Motion Table. Each sprite takes up four bytes in the table. The first byte specifies the (Y) velocity of the sprite, the second byte specifies the (X) velocity of the sprite. The third and fourth bytes are used by the interrupt routine so all you have to do is remember to leave space for them in the table. The following are allowed as values for (X) and (Y) velocities, also shown are direction of travel:
Hex
Motion
Description
Positive velocities. Down or right motion. Negative velocities. Up or left motion.
A value of 1 (>01) will cause the sprite to move one pixel every 16 VDP interrupts. This is approximately once every 16/60ths of a second. To summarize, in order to put sprites into motion you must:
1. 2. 3.
Enable
The number of sprites in motion must be placed in CPU RAM address >837A. Place descriptions of motion in the Sprite Motion Table which begins at VDP address >0780.
We will now create some programs to illustrate the points covered in this chapter. The first program will place a standard sized sprite in the center of the screen, but we will not put it in motion just yet: ****************************************************** 001 002 * * 003 * Program to place a red ball-shaped sprite * 004 * in the center of the screen. * 005 * * 006 ******************************************************
007 008
009 * 010 SATAB
START VMBW
>0300 *SPRITE ATTRIBUTE TABLE.
122
011 012 013 014 015 016 017 019 020 021 022 023 024 025 026 027 028 029 030
EQU
>0400
DATA >3C7E,>FFFF,>FFFF,>7E3C DATA >70D0,>8008 DATA >D000 BSS LWPI LI LI LI BLWP LI LI LI BLWP JMP END >20 MYREG RO,SDTAB R1,BALL R2,8 @VMBW RO,SATAB R1,SPAT R2,8 @VMBW LOOP START
LOOP
Most programmers think of sprites when referring to moving graphics. Sometimes other methods of imparting motion to characters on the screen are better suited for certain situations. The following program will place six red ball-shaped characters on the screen and scroll the screen upwards moving the characters with it. If you run this program you will notice that the motion of the characters is somewhat jerky, this is because sprites are not used: 001 002 003 004 005 006 007
* * Place 6 ball-shaped characters on the screen & scroll * * the screen upwards. This is an example of how to * * put graphics into motion without using sprites. * * ***********************************************************
*********************************************************** *
*
GRAPH VSBW,VMBW,VMBR
>0384
>0908 >20
* *
GRAPH
* * * *
LOAD FOREGROUND & BACKGROUND COLORS OF BALL CHARACTER INTO COLOR TABLE
123
023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064
* LI LI LI BLWP * LI LI LI BLWP AI DEC JGT BSS BSS CLR LI LI BLWP LI LI LI BLWP * LOOP1 CLR BLWP AI CI JHE BLWP AI JMP RO @VMBW R0,>40 R0,>300 OUT @VMBR RO,>FFE0 LOOP1 R0,325 R1,>2100 R2,6 @VSBW R0,33 R2 LOOP >20 >20 RO R1,LINE1 R2,>20 @VMBW RO,>20 R1,LINEX R2,>20 @VMBR * * * * PLACE 6 BALL SHAPED CHARACTERS ON THE SCREEN ONE AT A TIME IN DIFFERENT SCREEN POSITIONS ARE ALL SIX ON SCREEN YET? RESERVE MEMORY TO HOLD SCROLLED LINES OF SCREEN SAVE TOP SCREEN ROW (BEGINNING WITH POSITION >000) IN LINE1 RO,PATTAB R1,BALL R2,8 @VMBW * * * * LOAD THE BALL PATTERN INTO THE PATTERN DESCRIPTOR TABLE
LOOP
* * * * * * * *
* * *
* * * * * * * * * * * * *
EACH SCREEN ROW IS SUCCESSIVELY READ INTO LINEX AND THEN PRINTED IN THE ROW POSITION JUST ABOVE IN ORDER TO SCROLL THE SCREEN "UP" WHEN THE LAST ROW IS REACHED THE PROGRAM JUMPS TO "OUT" PRINT FIRST LINE IN LAST ROW
* OUT
The source code Jisting on the next page places our red ball on the screen as a sprite instead of as a graphic. It also places the sprite in motion from left to right across the screen. By pressing any key you can change the magnification of the sprite. The sprite is moved by successively changing its X-location on
124
the screen.
00 1
002 003 005 006 007 008 009 010 011 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054
**** ****** ******* ******* ****** ******* ******* ****** ******* **** * *
* CALL SPRITE * * * THIS PROGRAM PLACES A RED BALL-SHAPED SPRITE IN * MOTION ACROSS THE SCREEN BY SUCCESSIVELY ALTERING ITS * * X--LOCATION. PRESSING ANY KEY ALTERS THE MAGNIFICATION * * * ************************************************************* DEF MOTION REF VSBW,VMBW,VSBR,VWTR,KSCAN KBOARD EQU >8375 SKEY EQU >8374 SATAB EQU >0300 SDTAB EQU >0400 * BALL DATA >3C7E,>FFFF,>FFFF,>7E3C SDATA DATA >7080,>8008 DATA >D000 * STATUS EQU >837C SET DATA >2000 MYREG BSS >20 * SPRITE LWPI MYREG * CLR @KEYBOARD * KEYBOARD DEVICE=0; SCAN ALL KEYS LI RO,SDTAB * LOAD LI R1,BALL * SPRITE LI R2,8 * DESCRIPTOR BLWP @VMBW * TABLE * LI RO,SATAB * LOAD LI R1,SDATA * SPRITE LI R2,6 * ATTRIBUTE BLWP @VMBW TABLE * * LOOP LI RO,SATAB+1 * READ BLWP @VSBR * GET X POSITION OF SPRITE AND SRL R1,8 * SUBTRACT 1 FROM X (X-1) DEC R1 * JNE MOVE * IF X=0 THEN LI R1,>00FF * LET X=>FF * MOVE SLA R1,8 * WRITE NEW X POSITION BLWP @VSBW * CLR R8 * THIS IS A SHORT DELAY TO * SLOW DOWN THE SPEED OF THE DELAY INC R8 CI R8,800 * SPRITE (FOR I=1 TO 800) JNE DELAY * *
125
056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084
OUT
* * * *
* * R6 IS USED AS A COUNTER TO KEEP CHECK INC R6 * TRACK OF WHICH MAGNIFICATION R6,4 CI * LEVEL (1 TO 4) WE ARE ON. JLT GO * CLR R6 * * SELECT R6,1 GO CI * NEXT JEQ MAG * CI R6,2 MAGNIFICATION * JEQ DSIZE LEVEL * R6,3 CI * JEQ DSIZEM * SMALL LI RO,>01E0 * LOAD RO WITH THE PROPER VALUE JMP WRITE * TO LOAD INTO VDP REGISTER 1 IN MAG LI RO I >01E1 * ORDER TO CHANGE THE JMP WRITE * MAGNIFICATION DSIZE LI RO,>01E2 * JMP WRITE * DSIZEM LI RO,>01E3 * * ************************************************************* * * ACTUALLY LINES 066 THROUGH 079 TAKE UP A GREAT DEAL * OF MEMORY. CAN YOU SUM UP THESE LINES OF CODE INTO * * A SIMPLE TWO LINE STATEMENT THAT WOULD WORK AS WELL? *
085 *************************************************************
086 * 087 WRITE BLWP @VWTR 088 @LOOP B 089 END MOTION
This next source code listing again places our red ball on the screen as a sprite. The ball is magnified and is moved using automatic sprite motion. The LIMI 2 instruction is present to allow interrupts to occur. Keep in mind that automatic sprite motion cannot occur without interrupts. 001 ************************************************************ 003 * CALL SPRITE * 004 * THIS PROGRAM PLACES A MAGNIFIED SPRITE ON THE SCREEN AND * 005 * PUTS IT IN MOTION USING AUTOMATIC SPRITE MOTION * 006 ************************************************************ 007 DEF START 009 REF VMBW,VWTR 010 * 011 NUMB EQU >837A 012 SATAB EQU >0300
126
013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044
EQU EQU DATA DATA DATA DATA DATA BSS LWPI LI LI LI BLWP LI LI LI BLWP
>0400 >0780 >3C7E,>FFFF,>FFFF,>7E3C >70D0 >8008 >D000 >0505,>0000 >20 MYREG RO,SDTAB R1,BALL R2,8 @VMBW RO,SATAB R1,SDATA R2,8 @VMBW RO,SMTAB R1,SPEED R2,4 @VMBW
* * * * * * * * * * * * * * * * * *
LOAD SPRITE DESCRIPTOR TABLE LOAD SPRITE ATTRIBUTE TABLE LOAD SPRITE MOTION TABLE INDICATE NUMBER OF SPRITES IN MOTION (1) IN ADDRESS >837A ENABLE INTERRUPTS ENDLESS LOOP TO HOLD DISPLAY ON THE SCREEN
* LI LI LI BLWP * LI R1,1 SLA R1,8 MOVE R1,@NUMB * LIMI 2 JMP $ END START
-127-
128
The following steps summarize what must be done in order for your program to produce sound: 1. Load the Sound Table which begins at VDP address >83CC with sound data. Set the least significant bit of the byte located at CPU address )83FD to indicate to the computer that the Sound Table is in VDP RAM. Enable interrupts by using the LIMI 2 instruction.
2.
3.
Once all the above conditions are met, you can start the sound generator by placing a value of 01 at CPU address >83CE. This address is used by the interrupt routine as a count-down timer during sound generation. NOTE: You will have to disable interrupts if you are going to read or write to VDP RAM because the interrupt routine may alter the read/write address. If your program has a key scanning loop this may be a good place to enable/disable your interrupts. See page 81 for an example.
(?_(14 THE
BoluNin
-Irdcs Eci__
In order to produce sound you must construct a Sound Table that describes the characteristics of the sound you wish to produce. The TI Home Computer has the ability to produce up to three separate tones simultaneously. It can also produce a number of different "noise" sounds. Up to three tones and one noise can be produced simultaneously. The computer has three tone generators labeled 1, 2, and 3. Noise is produced by a separate noise generator. In order to produce a tone you must enter the following information into the Sound Table: 1. 2. 3. 4. Specify Specify Specify Specify which TONE GENERATOR is to produce the tone. the FREQUENCY of the tone. the VOLUME of the tone. the DURATION of the tone.
To produce noise you must enter this information into the Sound Table: 1. 2. 3. 4. Specify Specify Specify Specify WHITE or PERIODIC noise. SHIFT RATE (type of noise). VOLUME of noise. the DURATION of the noise.
129
All the bytes that describe the characteristics of a tone or noise except one are referred to as specification bytes. The exception is the DURATION byte which is not considered a specification byte. It takes a total of three specification bytes to hold the generator number, volume and frequency of a tone. Table 9.0 outlines the contents of each of the three bytes. It should be noted now that the frequency is not entered as such (that would be to easy). Instead it is entered as a "frequency code" which we will have more on later.
TABLE 9.0 SPECIFICATION BYTES FOR TONES Byte Bit# Holds The following Information:
/ 0
ONE
\
1-2
3 4-7 0-1 2-7 / 0 1-2 \ 3
This bit is always set (=1). Specifies the Sound Generator. This bit is reset (=0). Contains the 4 least significant frequency code bits. These bits are always reset (=00). Contains the 6 most significant frequency code bits. This bit is always set (=1). Indicates Sound Generator used. This bit is set (=1).
TWO \ THREE
4-7
Volume level.
All the noise information requires only two specification bytes. They are structured as outlined in Table 9.1: TABLE 9.1 SPECIFICATION BYTES FOR NOISE Byte Bit#
0 / 1-2
ONE \
3
4 5 6-7 0 1-2 3 4-7
TWO
\
130
Bits 1 and 2 in all bytes refer to one of the three tone generators or the noise generator. A bit configuration of 00 selects tone generator #1. A bit configuration of 01 selects tone generator #2. A bit configuration of 10 selects tone generator #3. Finally, a bit configuration of 11 selects the noise generator. Table 9.2 illustrates several examples of the structure of tone and noise bytes. An X in a bit position is for frequency or volume information that we will cover later.
TABLE 9.2 EXAMPLES OF TONE AND NOISE SPECIFICATION BYTES Bit configuration
1000 XXXX 00XX XXXX 1001 XXXX
Byte #
1 --) .,_ 3 .... 1 2 .,_ 3 1 2 3 1 2 3
Description
Toe Lenerator # 1
1010 XXXX 00XX XXXX 1011 XXXX 1100 XXXX 00XX XXXX 1101 XXXX 1110 XXXX OOXX XXXX 1111 XXXX
Tone Generator # 2
Tone Generator # 3
Noise generator
P- Ftactli
(7.1711rE
You may think that plugging in the desired frequency into the Sound Table is all there is to it. However, it is not that easy. First of all the frequency must be converted into a frequency code which is then loaded into the table. The frequency code is defined as half the period of the specified frequency. To save you a lot of time trying to figure out what this means you can use the following formula: 111860.8 = Frequency Code Frequency Suppose we want to find the frequency code for "middle C" which has a frequency of 523.25 . We simply plug this value into our formula as follows:
131
We easily find that the proper frequency code equals 213.8, a value that rounds up to 214 OOD6). The most significant 6 bits (bits 0-5) of the frequency code are placed in bits 2 through 7 of our second specification byte. The four least significant bits of the frequency code are placed in bits 4 through 7 of our first specification byte. If this sounds a bit confusing don't worry, actually its quite simple. For example, suppose we wanted to define the first two specification bytes of a tone with a frequency of 392 HZ. Further, we want to produce this tone on generator #1. We find from our formula the frequency code which equals 285 or >11D.
1000 XXXX
00XX XXXX
= >8---
Here we have selected generator #1. Now we will take our frequency code >11D and place its 4 least significant bits (>D) in bit positions 4 through 7 of our first specification byte: 1000 1101 00XX XXXX = >8D--
Finally, we take the most significant 6 bits of our frequency code (>11) and place them into bit positions 2 through 7 of our second specification byte: 1000 1101 0001 0001 = >8D11
We now have created the first two specification bytes required to produce a tone of 392 HZ on tone generator # 1. The following are some additional examples: 1000 0110 0000 1101 0000 1011 C>860D]
0011 1111
C>AEOB] C>C93F3
Gen #1 freq = 523.25 Gen 412 freq = 587.33 Gen #3 freq = 110.00
The third specification byte required for tones holds the volume of the tone. It also holds the value of the generator number you are referring to as did the first specification byte. The volume is held in bit positions 4 through 7 of the third specification byte for tones. Its value can range from 0 (loudest) to 30 (no sound). When determining the volume level these four bits may be thought of as having a binary zero following them. In this way a volume level of 0001 may be considered as 00010. The following are some examples of the third specification byte:
TURNS OFF GENERATOR #1 VOLUME LEVEL = GENERATOR #2, VOLUME LEVEL = 0 NOISE GENERATOR, VOLUME LEVEL = 6 GENERATOR #3, VOLUME LEVEL = 28
30
132
To produce a noise requires only two specification bytes to be loaded into the Sound Table. Referring to Table 9.3 gives the bit values to be loaded into the first specification byte for the desired noise. The second specification byte holds the volume level and is constructed the same way the third specification byte for a tone is constructed except that you specify the noise generator instead of a tone generator.
Bits 6 & 7
00 01 10
Description
"Periodic Noise" Type 1 "Periodic Noise" Type 2 "Periodic Noise" Type 3 "Periodic Noise" varies with the frequency data in tone generator #3 "White Noise" Type 1 "White Noise" Type 2 "White Noise" Type 3 "White Noise" varies with the frequency data in tone generator #3
0 1
1 1
11
00 01 10 11
Suppose we wanted to construct the two required noise specification bytes for a Type 3 Periodic Noise with a volume level of 6. From Tables 9.1 and 9.3 we put together the first byte like so:
1111 0010
E>F23
The second specification byte containing the volume information would look like this:
1111 0011
EI.L
C>F3]
The DURATION byte is not considered a specification byte. It informs the tone or noise generator how long the tone or noise will last. It is measured in sixtieths (1/60) of a second. Possible values range from 0 (>00) no sound, which stops the generator, to 256 (>FF) which is approximately 4.25 seconds.
LADAinilmoi
imila
(DiultNin
-iric
One last thing to note before we begin constructing a Sound Table is that when you are setting up a byte table you must indicate the number of specification bytes that you are going to feed to the
133
sound generator. For example, if you wanted to specify a tone with a frequency of 110 HZ, a volume of 2 and a duration of 0.5 seconds on generator #1, the specification and duration bytes needed are: >03,>89 1 >3F,>91,30 The first byte (>03) indicates that there are 3 specification bytes to load into the sound generator. The second and third bytes (>893F) tells us that on generator #1 (>8---) a tone of 110 HZ (>-93F) is desired. The fourth byte (>91) sets the volume level of generator #1 at 2. The last byte (30) specifies a duration of 30/60ths of a second for the tone. The following are some additional examples of values to load into the Sound Table:
-3 specification bytes to load 1 -Tone Generator #1 tone -Frequency = 392.00 FC = >11D -Volume level = 2 -Duration = 20/60ths second 2. >3,>A6,>0D,>85,244 -3 specification bytes to load 1 -Tone Generator #2 tone -Frequency = 523.25 FC = >0D6 - Volume level = 10 (0101 0) - Duration = 244/60ths second
-9 specification bytes to load 3 -Tone Generators #1, #2, & #3 tones -Frequencies = 329.63, 523.25 and 739.99 - Volume levels G1=2, G2=10, G3=20 -Duration = 10/60ths second 4. >2,>E5 1 >FE,119 -2 specification bytes to load -Noise Generator (>E0) -White Noise, Type 2 (>05) -Volume level = 28 -Duration = 119/60ths second >1,>9F,0 -This data will terminate the sound in Generator #1.
1 noise
5.
134 6.
LET THERE BE SOUND >0B,>8E,>OF,>AD,>17,>CC,>1F,>E3,>90,>B6,>D3,>F6,249 -11 specification bytes to load -Tone Generators #1, #2, #3 and noise generator -Frequency = 440.00, 293.66, 220.00 -Periodic Noise of the type that varies with the frequency data loaded into tone generator #3. -Volume levels G1=0, G2=12, G3=6, NG=12 -Duration = 249/60ths seconds.
The following source code can be used to access the sound controller and start sound processing. * Begin Sound Table at VDP Address >1000 SOUNDT EQU >1000 ONE BYTE >01 . START LI R10,SOUNDT * * Put VDP address that Sound Table . MOV R10,@>83CC * begins at in CPU address `-83CC SOCB @ONE,@83FD * Sound Table is in VDP RAM. MOVES @ONE,@>83CE * Start sound processing. LIMI 2
The following program plays "HOME ON THE RANGE" on your computer. Note how all three tone generators are used together to produce multiply notes.
001 *********************************************************** * 002 * * 003 * Program plays "HOME ON THE RANGE" on your computer. * 004 * 005 ***********************************************************
006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 DEF REF * MYREG SOUNDT ONE * START BSS EQU BYTE EVEN LWPI LI LI LI BLWP START VMBW >20 >1000 >01 MYREG RO,SOUNDT R1,SDATA R2,274 @VMBW
* * * * * *
* LOOP1
LET THERE BE SOUND 023 024 027 029 LOOP2 030 031 032 * 033 SDATA 034 035 036 037 038 039 040 041 042 043 * 044 045 046 047 048 049 050 051 052 053 054 055 * 056 057 058 059 060 061 062 063 064 065 066 * 067 068 069 070 071 072 073 074 075 076 077 078 SOCB @ONE,@83FD MOVB @ONE,@>83CE LIMI 2 MOVB @>83CE,@>83CE JEQ LOOP1 JMP LOOP2 BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE END
135
* When CPU address >83CE = 0 * sound processing is * finished & program repeats
>03,>8D0.110.91,40 >04 1 >AD I >110.9F,>B1,40 >03,>A6,>ODOS1 1 40 >06,>8E0.0B,AD,>11,>95,>B5,40 >090.8A0. 0A,>A6,OD,CD,>11,>95,B5 1 >D5,60 >05,>86,>OD,>91,>BF,>DF,20 >030.8200E 9 ).91,40 >030.8E,OF0.91,40 >03,>800.0A,>91,40 >04 1 >A0,>0A,>9F,>B1 1 40 >09,>80,>0A 1 >A6,>ODO.CD,>100.950.B50.D5,60 >050.80,>0A,>91,BF,DF,20 >03,>80,>0A,>91,20 >03,>817 0.08,>91,40 >09,>8A,>0A,>A60.0DO.CD,>110.95,B5 I D5,40 >05,>860.0D0,9102F,DF,20 >04,>A6 1 >OD0.9F021,40 >05 1 >C6,OD,>9F 1 >BFO.D1,40 >03,>C2,>OE,>D1,40 >03,>C6,>OD,>D1,40 >03,CE,OB,>D1 1 80 >03 1 >CD,>11,D1,40 >04,>8D,>110.91,>DF,40 >03,>86,OD,>91,40 >06,>8E,>OB,>AD,>11,>93,>B3,40 >09,>8A,>0A,>A6,ODOCD,>110.950250.D5,60 >05,>860.0D,>91,BF,DF,20 >03,>82,>OE,>91,40 >03,>8E0.0F I >91,40 >03,>80,>0A,>91,40 >04,>A00.0A0.9F,>B1,40 >06, >80, >OA, >AD, >10, >93, >B3, >60 >04,>80,>0A,>91,BF,20 >04,>A000A,>9F021,40 >09 1 >8A,>0A 1 >A6,>OD I >CD,>11,>950.B5,>D5,50 >05,>8E,>OB,>91,>BF,>DF,>30 >030.86,>0D,>91,40 >090.820.0E,AD I >11,CD,>17 1 >95,B5,D5,40 >05,>86,OD0.91,>BFODF,40 >030.8E 9 M:30'91,40 >03 1 >86,ODO.91,100 >01,>FF,0
136
The following table gives you a quick reference guide for frequency specification bytes (specification bytes #1 & #2). Simply look up the desired note or frequency and follow it over to the DATA column to get the first two specification bytes. The DATA in Table 9.4 always refers to tone generator #1. If you want to produce the tone on generator #2 change the first nybble of the DATA to >A. To produce the tone on generator #3 change the first nybble of the DATA to >C. For example, to produce a tone with a frequency of 5587.65 on generator #2 the DATA would be >A401.
OCTAVE
6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 4 4 4 4
FREQUENCY
5587.65 5274.04 4978.03 4698.64 4434.92 4186.01 3951.07 3729.31 3520.00 3322.44 3135.96 2959.96 2793.83 2637.02 2489.02 2349.32 2217.46 2093.00 1975.53 1864.66 1760.00 1661.22 1567.98 1479.98 1396.91 1318.51 1244.51 1174.66 1108.73 1046.50 987.77 972-33 880.00 830.61 783.99
FREQUENCY CODE
>014 >015 >016 >018 >019 >01B >01C >01E >020 >022 >024 >026 >028 >02A >02D >030 >032 = >03C >040 >043 >047 >04C >050 >055 >05A >05F >065 >06B >071 >078 >07F >087 >08F
DATA
>8401 >8501 >8601 >8801 >8901 >BB01 >8C01 >8E01 >8002 >8202 >8802 >8602 >8802 >8A02 >8D02 >8003 >8203 >8503 >8903 >8CO3 >8004 >8304 >8704 >8C04 >8005 >8505 >8A05 >8F05 >8506 >8806 >8107 >8807 >8F07 >8708 >8F08
F
E D# D C# C B A# A G# G
4 4 4
4
4
4 4 4 3 , ..) 3 ..... ,:, 3
137
(Continued)
DATA >8709 >800A >840A >840B >BEOB >BAOC >860D >820E >800F >8EOF >8D10 >8D11 >8E12 >8014 >8315 >8816 :::.8D17 >8419 >8C1A >851C >801E >8C1F
FREQUENCY CODE >097 >0A0 >OAA >0B4 >OBE >OCA >0D6 >0E2 >OF >OFE >10D >11D >12E >140 >153 >168 >17D >194 >1AC >105 >1E0 >1FC >21B >23B >25D >281 >2A7 :::.2CF >2FA >327 >357 >38A >3C0 >3F9
Anal
>8B23 >8D25 >8128 >872A >8F2C >8A2F >8732 >8735 >8A38 >803C >893F
NOTE: If you need to find a note that is a half-step higher than a given note, you can use the following formula:
10
-139-
140
ic."_c"
-T- IHI
ecia_wc
oppla e -renimlaml-
As with the Editor/Assembler each source code statement is made up of four fields. These fields are named and arranged as follows: LABEL OPCODE OPERAND COMMENT If you do not specify a LABEL then you must leave a space before typing in the OPCODE. If you use a LABEL the first character must be alphabetic. The second may be any alphanumeric character. The LABEL field when using the Line-by-Line assembler is limited to 2 characters in length. This is our first major difference over the Editor/Assembler which can have LABELS up to 6 characters in length. The OPCODE, OPERAND and COMMENT fields are all constructed as outlined in section 3.3 of Chapter 3.
10-1
irNBlarlEgt.
EllI
T- I",,,
There are 7 assembler directives that are recognized by the Line-by-Line assembler. They are:
Absolute ORigiN Block of memory Starting with Symbol Word definition (initialization) END program Let a LABEL represent a constant String constant definition (initialization) Call up SYMbol table
The Directives BSS, DATA, EQU and TEXT are used exactly as outlined in Chapter 5 entitled 'ASSEMBLER DIRECTIVES'. The functions of the remaining directives are outlined in the following sections.
AORG
>7D00
the Location Counter will now be set to location >7D00 and the contents of this location will be displayed. If you were to
141
type in a new source statement and press enter memory location >7D00 would now contain the new value and the Location Counter would advance to address >7D02. There are basically two main uses for the AORG directive. The first is to point to where you begin entering your program. The second use is to correct errors in the code after you have entered them. To illustrate these two points consider that we are entering the following program where #### represents whatever number happens to be held in a paticular address:
Instruction
Comments
MOMS *CM
7D00 0000 7D20 0201 7D22 7D00
MW
* Go to this address to load program. * Reserve my workspace area. * Put pointer to workspace. * Load a value into R1. * Load a value into R2. * Load a value into R3. * Branch & Link with subprogram S1.
Mw
'! -5
tAt,-)
41
4s o
Rt
LI BL
7D34
Lets say we have reached this point on entering our program and found that we have made a mistake; instead of loading a value of 30 into R1 we wanted instead to load a value of 32. To get back to address :>7D24 and change the value we use the AORG directive as illustrated below:
AORG LI AORG
* Return to address of mistake. * Insert corrected code. * Go back to where we left off. * Continue entering program.
B Ise MEI 01 L.. "1". Pt El L.. IE
ID I 3F " IAN
When programming with the Line-by-Line assembler you will specify symbols for operands that have not yet been defined. For example, you may write the instruction JMP S1 where S1 is a destination further along in the program (a point you have not reached to type in yet). The Line-by-Line assembler must keep track of these references somewhere until they are defined by you. These references are kept in a SYMBOL TABLE until you resolve them.
142
By typing in SYM you can call up the Symbol Table to review references which are unresolved. There are 3 categories within the Symbol Table. These categories and their contents are outlined in Table 10.0. TABLE 10.0 CATEGORIES OF THE SYMBOL TABLE Category RESOLVED REFERENCES Contents These are any symbols that have already been defined. These are any symbols that are undefined and are not referenced by a jump instruction. These are any symbols referenced by a jump instruction.
To see how the SYM directive works lets consider the following example: Location & Contents
Instruction AORG BSS LWPI LI EQU BL JMP SYM >7D00 32 MW R1,A1 >0400 @S1 S7
Comments * Starting address of program. * Reserves workspace area. * Load pointer to workspace area. * Load R1 with undefined data. * Define Al. * Branch & Link to undefined point. * Jump to undefined destination. * Now call up Symbol Table.
7D00 0000 MW 7D20 0201 7D22 7D00 7D24 0201 R0000 7D28 0202 AI 7D26 *0400 7D28 06A0 7DRCR 1OFF 7D2E ####
RESOLVED REFERENCES MW-7D00 A1-0400 UNRESOLVED REFERENCES (WORD) S1-7D2A UNRESOLVED REFERENCES (JUMP) 97-7D2C 7D2E **WI * Ready for next instruction.
If a category has no symbols associated with it, that category is not printed on the screen. If all three categories are empty, the SYM directive is erased and the assembler waits for you to
143
enter the next instruction. A maximum of 32 unresolved references can be displayed by the Symbol Table.
After you enter the END directive the statement: #### UNRESOLVED REFERENCES
will be displayed on the screen where #### is the number of references that you have not yet resolved. You must go back and figure out which ones they are (by using the SYM directive) and resolve them before attempting to exit from the assembler.
10-12 laniirime
The assembler retains some of the source code in a nine-page buffer which you can review by using the up and down keys to scroll the screen. When the buffer is filled the assembler scrolls back onto the screen to indicate that the buffer is full. Any additional instruction that are entered will overwrite previously written lines in the buffer. Because of this it is a good idea for you to keep a written copy of your source code so that you can refer to it when programming.
Once you start typing a line you cannot "back-up" with the arrow keys to correct a typing error. If you have not pressed "ENTER" you can delete the whole line by pressing "ERASE" and then retyping the entire line correctly. If you have already pressed ENTER then you have to return to that address by way of the AORG directive to change it. If you do not use the label field you can move right to the OPCODE field by simply pressing the SPACE BAR once. You can then move to subsequent fields by pressing the SPACE BAR again.
144
I a Ft: Fc C II FC
IHI IA NI ID L_. I NI ID
When entering source statements, the Line-by-Line assembler will display an ERROR message under one of three conditions: 1. If you attempt to redefine a previously defined label. For example:
AORB >7D00 7D00 0200 MW BSS 32 7D20 02E0 LWPI MW 7D22 7D00 7D24 0200 MW *ERROR*
2. If you attempt to enter an undefined opcode or directive. For example:
7D00 ####
JO] JI
IR: la IF' la IR la N11 IC la ./ .13 la F-- I INII I -1- I C3 INI "T ink 1E4 It_ la
Once you have finished entering your program you must also enter the program name and location of its starting point in the REF/DEF table so that mini memory module can find it.
145
The following is a short program that will print a message on the screen. We will then demonstrate how to use assembler directives to enter its name and starting point in the REF/DEF table: AORG >7D00 7D00 #### WS BSS 32 7D20 #### MW EQU >6028 * EQUATE VMBW UTILITY. 7D20 484F Al TEXT 'HOW ARE YOU?' * MESSAGE TO DISPLAY. 7D22 5720 7D24 4152 7D26 4520 7D28 594F 7D2A 5535 7D2C 02E0 ST LWPI WS * POINTER TO WORKSPACE AREA. 7D2E 6028 7D30 0200 LI R0,138 * SCREEN TABLE LOCATION. 7D32 008A 7D34 0201 LI R1,A1 * BEGINNING OF MESSAGE. 7D36 7D20 7D38 0202 LI R2,12 * # OF BYTES TO WRITE. 7D3A 000C 7D3C 0420 BLWP @MW * BRANCH TO VMBW UTILITY. 7D3E 6028 7D4OR1OFF JMP $ * HOLD DISPLAY ON SCREEN. 7D40*1OFF 7D42 END Assuming that you have just entered the preceding program exactly as written and have not exited from the assembler, the screen will appear as follows: 7D42 #### END 0000 UNDEFINED REFERENCES Do not press ENTER at this point (if you do you will exit from the assembler). Instead you should enter the following code to place the program name and starting location in the REF/DEF table so that you may run the program: 7D42 #### AORG >701C >7D42 is the first address that is not used in your program. That is, it is the First Free Address in the Module (FFAM). #### represents whatever value happens to be contained in address >7D42. Address >701C holds the FFAM. 701C #### #### represents the address of the old FFAM. We need to put the new FFAM (>7D42) here.
146
701C
7D42
DATA
>7D42
Remember, FFAM is the First Free Address that follows your program, in this case >7D42. Address >701E holds the Last Free Address in the Module (LFAM). Subtract this value from the FFAM; if the difference is 7 bytes or more, you have enough room to insert your program name.
701E
7FE8
701E
7FE0
DATA
>7FE0
Subtract 8 bytes from the old LFAM and place the result at address >701E like we have done here by using the DATA directive. Location counter advances to here displaying any data located at this address. We now need to jump to the REF/DEF table and enter our program name.
7020
####
7020
#### AORG
>7FE0
Jump to new entry point in REF/DEF table. >7FE0 #### Data at this address is displayed. Enter the program name as PRINT1. The program name must be exactly 6 characters long. The characters making up the name are stored in six bytes beginning at location >7FEO. Location counter advances to this next location, where we will define the 2-character entry point into our program.
'PRINT1'
7FE6
####
7FE6
7D2E
DATA
ST
Entry point at where we want program to start running. Enter the END directive and press ENTER to leave the assembler.
7FE8
####
END
We can now run this last program by selecting the RUN option from the MINI MEMORY selection list and typing in PRINT1 for the PROGRAM NAME? prompt and pressing ENTER.
147
To summarize, in order to run your assembly program you must: 1. 2. Place new FFAM at address >701C. Compare new FFAM with LFAM to see if there is a difference of 7 bytes or more. If there is then you can proceed. Subtract 8 bytes from old LFAM and place the resulting value at address <701E with a DATA directive, Jump to new LFAM and by using a TEXT directive enter your program name which must be exactly 6 characters in length. Define the entry label into your program with a DATA directive at address LFAM+6.
3.
4.
5.
If you have a disk memory system, you can use the LOAD AND RUN option of the MINI MEMORY module to execute assembly programs that were written using the Editor/Assembler system. When the minimemory comes across a BLWP @VMBW instruction while it is loading from a disk system, it will look up the address it needs in order to use the required utility. It will do this with all subsequent utilities it encounters. Thus, even though you can not create a program with the lineby-line assembler using the instruction BLWP @VMBW you can RUN programs that contain these symbols with the mini-memory module when the LOAD AND RUN option is used. All predefined symbols in the Editor/Assembler will load correctly into the Mini-Memory Module because they are all predefined in an internal table used by the loader.
1 0 .. 'ffi
You can save your assembly language program on cassette tape in the following manner: 1. 2. 3. Select EASY BUG option from the selection menu. Use the S command. You can enter the actual starting and ending address of your program, but it is recommended that you enter a starting address of >7000 and an ending address of >7FFF in order to include the REF/DEF table and pointers. If you do not do this you will have to re-enter the program name in the REF/DEF table every time you load the program.
148
i (7.) -
e.
ul -r
1 L.
All the utility programs discussed in chapter 6 are available when using the Line-by-Line assembler. However the Line-by-Line assembler does not recognize the predefined symbols that the Editor/Assembler package does. With the Line-by-line assembler you simply cannot reference the needed utilities, you have to branch directly to the address the utility is located at. The following routine is an example of how utility programs are accessed when programming with the Line-by-Line assembler.
Instruction AORG >7D00 BSS 32 LWPI MW EQU >6018 CLR R1 MOVB R1,@>837C BLWP @GP DATA >0034 END
Comments
7D00 7D20 7D22 7D24 7D24 7D26 7D28 7D2A 7D2C 7D2E 7D30
*Mt* 02E0 7D00 41#404) 04C1 D801 837C 042A 6018 0034 ####
MW
* *
* GPLLNK begins @>6018 * Set status byte=0 * * * BL with GPLLNK * Accept tone routine * Exit assembler
GP
This short program uses an equate directive to create a symbol (GP) for the GPLLNK utility which begins at address >6018. Of course, the program could have just as easily referenced the address directly. The following table lists the available ROM utilities and their respective addresses.
Address >6018 >601C >6020 >6024 >6028 >602C >6030 >6034 >6038 >603C >6040 >6044 >6048 >604C >6050 >6FOE >6FFF
11
-149-
150
The CALL CLEAR BASIC routine clears the screen by placing a space character in all screen positions. To understand how assembly language accomplishes this we must first understand how the compute creates a 'screen'. The computer has no concept of a screen; it views the screen as one continuous series of memory locations. There are no rows and columns, only 768 possible character locations numbered beginning at the upper left of the screen at 000 and continuing to the bottom right hand corner 767. These memory locations are in VDP RAM beginning at address >0000. Figure 11.0 illustrates this below:
FIGURE 11.0 1 1 1 1 000 001 002 003 004 005 . . 032 033 034 035 064 065 066 . . . 096 . . 1 . 1 . 1s . si .
1 1 s 1
i
. . .
.
. . . .
.
1 736 .
767 1
To convert a BASIC row and column position into a assembly language graphic screen position we use the following algebraic expression:
C C + (R*32) 3 = SP
Where 'C' is the column number, 'R' is the row number and 'SP' is the resulting screen position. For example, to find the screen position of (5,7) we simply plug in the values:
E 5 + (7*32) 3 = 229
151
Clearing an entire screen is accomplished by placing a space character (32 or >20) in all successive screen locations as demonstrated in the following routine:
001
* * This module will place a space character in all * * screen positions. * * *********************************************************** DEF BEGIN 008 REF VSBW 009 * Reserve memory for my workspace. 010 MYREG BSS 32 011 * * Set pointer to workspace area. 012 BEGIN LWPI MYREG R0,0 * First screen position to print to. 013 LI R1,>2000 * Load space character. 014 LI R2,767 * Load our count register. LI 015 * Place character on screen. BLWP @VSBW 016 LOOP * Increment screen position by 1. 017 INC RO * Decrement our count register. DEC R2 018 * See if whole screen filled. JGT LOOP 019 020 * * End program. END BEGIN 021 004 005 006 007
Lines 008-012 reserve memory for the Workspace Registers, set the workspace pointer at the beginning of this work area and reference all needed utility programs. Line 013 is the beginning of the working part of the program. It loads RO with the first screen position to receive a blank character (position 000). Line 014 loads character 32 (the blank space character) into the left byte of R1 as this is the byte that VSBW will utilize. Line 015 sets up R2 as a count register that will reach 0 when all screen positions are filled. Line 016 places the character on the screen and is the beginning of our loop. The first time this program runs through the 'LOOP' a blank space character will be written to VDP RAM address 0000. Lines 017 and 018 will increase RO by one and decrease the count register by one. The program will then jump back and write a space character in the next screen location. This will continue until the count register has been decremented to zero. When this happens the program will end. The loop in this program will execute a total of 768 times; filling VDP RAM memory locations 000 through 767 with the value for the space character.
The source code used to color the screen in BASIC is the 'CALL SCREEN' statement. It is quite similar to the source code
152
we used to mimic the CALL CLEAR routine. The difference is that the foreground and background color of the space character has to be redefined before we fill the screen with it. For example, if we make the foreground and background color of the space character black, then fill the screen with it, it will leave the screen appear black. The foreground and background color of a character is altered by changing the values of addresses in the Color Table. The Color Table begins at VDP RAM address >0380 and extends to address >039F. Each byte in the Color Table codes for the foreground and background of a group of eight characters. For example, VDP address >0380 holds the byte that codes for the foreground and background colors of character codes 0 through 7. Address >0381 holds the byte that codes for characters 8 through 15. Address >0382 holds the byte that codes for characters 16 through 23. This continues on until address >039F is reached which holds the byte that codes for the final character codes 248 through 255. Table 11.1 lists the Color Table addresses and character codes each byte holds the color of.
Char. Codes
0-7 8-15 16-23 24-31 128-135 136-143 144-151 152-159
Table Address
>0384 >0385 >0386 >0387 >0394 >0395 >0396 >0397
Char. Codes
32-39 40-47 48-55 56-63 160-167 168-175 176-183 184-191
Table Address
>0388 >0389 >0390 >0391 >0398 >0399 >0400 >0401
Char. Codes
64-71 72-79 80-87 88-95 192-199 200-207 208-215 216-223
Table Address
>038C >038D >038E >038F >039C >039D >039E >039F
Char. Codes
96-103 104-111 112-119 120-127 224-231 23 , -219 240-247 248-255
The space character is character 32 (HEX >20). Looking at the Color Table outlined in Table 11.1 we see that address >0384 holds the byte that contains the color code for character 32. As we already know there are eight bits in a byte. In the case of a color byte the left most four bits (4 most significant bits) code for the foreground color, while the right four bits (4 least significant bits) code for the background color. From this information we know that if we place a value of >Fl at address >0386 it will set characters 48 through 55 white on black. The following source code can be used to load a value into a color table address. In this case characters 32 through 39 are set black on black.
153
001 003 004 005 006 008 009 010 011 012 016 017 018 019 020 021 022 023 024 025 026 027
********************************************************** * * CALL SCREEN(2) * * PROGRAM MODULE TO LOAD VALUE (BYTE) INTO THE COLOR * * TABLE, THEREBY SETTING THE FOREGROUND AND BACKGROUND * * COLOR OF A DESIGNATED CHARACTER SET. ********************************************************** REF VSBW MYREG BSS 32 COLTAB EQU >0384 COLOR DATA >1100 BEGIN LWPI MYREG LI RO,COLTAB MOV @COLOROR1 BLWP @VSBW * LI R0,0 R1,>2000 LI LI R2,767 LOOP BLWP @VSBW INC RO DEC R2 JGT LOOP
Line 010 sets up the Workspace Register area. Line 011 sets COLTAB equal to 0384, the address in the table we want to write to. Line 012 defines the byte we will use, in this case >11, or black on black. Line 016 starts the program proper. Here we load the address of the Color Table into RO. Line 018 moves the byte we are going to write (>11) into the most significant byte of R1. Line 019 calls the utility program that executes the write. At this point address >0384 now contains the byte >11. Characters 32-39 are now set to black on black. Lines 021 through 027 are just the CLEAR SCREEN program that prints the space character in all screen positions, but now that character is set to black on black. The screen is now totally black except for the upper and lower border which can be changed by writing a value to VDP Register 7.
I) 1
To display a message somewhere on the screen in xBASIC you use the simple command:
154
numbered 000 to 767. To convert a row and column location into its memory location equivalent use the algebraic expression: C C + (R*32) 3 = P where C is the column, R is the row, and P is the assembly language memory location. Thus location (4,5) becomes: C4+(5*32)]=164 Now that we know the location on the screen where we want to put the message, we need to know how to store the message in the program until we print it out. This is done through the use of a "TEXT" directive. The following source code outlines the procedure to print something on the screen: 001 003 004 005 007 008 009 010 011 012 013 014 015 016 017 ************************************************** * DISPLAY AT(6,3):"HOW ARE YOU?" * * * PROGRAM MODULE TO PRINT A STATEMENT IN A * * DESIGNATED SCREEN POSITION. ************************************************** REF VMBW MYREG BSS >20 ADDR1 TEXT 'HOW ARE YOU?' * Message to print. * BEGIN LWPI MYREG * E6+(3*32)3 Screen location. R0,102 LI R1,ADDR1 * Load message. LI * # of characters to write. LI R2,12 BLWP @VMBW * Hold display on screen. JMP $
'CALL CAAAIR This BASIC statement redefines a specified character using a 16 character HEXadecimal coded string. For example character 33 C>213 is the ASCII value for the exclamation point (!). If we enter the statement: 100 CALL CHAR(33,"FFFFFFFFFFFFFFFF") then character 33 is redefined as solid square (all areas shaded). If we wanted to redefine a character into a ball shape, we could use the procedure on the following page which outlines a grid to help us create our pattern.
155
From the figure above it can be seen that the pattern identifier for the 'BALL' is "3C7EFFFFFFFF7E3C". We now construct the following statement: 100 CALL CHAR (128,"3C7EFFFFFFFF7E3C") Which defines character 128 as our "ball". We can then place the ball anywhere on the screen with a CALL HCHAR statement. The complete code is thus: 100 CALL CHAR(128,"3C7EFFFFFFFF7E3C") 110 CALL HCHAR(4,10,128,1) To understand how assembly language accomplishes the same task we must know where the computer stores patterns. It holds them in a Pattern Descriptor Table. This table begins at address >0800 and extends through to address >OFFF in VDP RAM. Each pattern requires eight bytes to define one character. The pattern of character 0 occupies addresses >0800 through >0807, character 1 occupies addresses >0808 through >080F, character 3 occupies addresses >0810 through >0817 and this continues until the last character, character 256, is reached which occupies addresses >0FF8 through >OFFF. To quickly find which address begins the code for which character, you can use the following formula: E 2048 + ( C*8 ) 3 = A Where 'C' is the decimal value of the character and 'A' is the decimal value of the desired address. Using this formula we can find that the address that begins the description of character 128 E>803 is : E 2048 + ( 128 * 8 ) 3 = 3072 which is VDP address >OCOO.
156
Now that we know the pattern identifier for a ball and the address of where that pattern belongs for character 128, we can write a translation of the following BASIC code: 001 002 003 004 005
006
007 008 009 010 011 012 013 014 015 016 017 018 019 020 021
REF VMBW,VSBW MYREG BSS 32 * PATTAB EQU >0000 * E20484-(C*8((3=0000 PAT DATA >3C7E,>FFFF,>FFFF,>3C7E * "BALL" pattern * START LWPI MYREG * Loads the pattern for the balll LI RO,PATTAB * into the Pattern Descriptor * Table. LI R1,PAT * . LI R2,8 BLWP @VMBW * . * LI R0,138 * Places the "ball" (character 128) * on the screen in position (4,10) LI R1,>8000 BLWP @VSBW * ' JMP $ * Hold display on screen.
By adding a few additional lines of code we can repeat the pattern any number of times in the horizontal direction. The following additional lines of source code when placed in the program above will simulate the BASIC statement:
CALL HCHAR(4,10,128,8)
Replace lines 018 through 025 with the following code:
.
018 LI R0,138 019 R108000 LI * R2,8 020 LI 021 LOOP BLWP @VSBW * * RO 022 INC * DEC R2 023 * 024 JGT LOOP 025 *
Count register: loop 8 times. Put character on screen. Next position to place character. Decrease count register. Check if all 8 characters are on screen, if not loop again.
To translate the VCHAR statement requires only a slight modification of the code for the HCHAR statement as illustrated on the next page (note only line 022 was altered):
157
LOOP DEC *
LI LI LI BLWP AI R2 JOT
R0,138 R10.8000 R2,8 @VSBW * Increment to screen position R0,32 * below last one written to. LOOP
You will notice that line 022 adds 32 to the current screen position that you are writing to. In this way the next screen location specified is the one directly under the previous one. This source code, when added to the program lines previously mentioned, is a direct translation of the BASIC statement: CALL VCHAR(4,10,128,8) In fact, by altering the amount that yoU increase *or decrease RO in your program you can make the patterns print up, down, diagonally or virtually any way by altering this one line of source code.
This BASIC command sets the keyboard to be tested and returns two variables based on input from the keyboard. The first variable tells you whether or not a key has been pressed, while the second variable returned gives you the value of the key pressed. There is a utility program in assembly language that you can use to return keyboard input. This utility is referred to as KSCAN. In order to use the KSCAN utility, you have to first determine where you want the input to come from. You can input from the whole keyboard, right side of the keyboard, left side of the keyboard or input from the joysticks. Address >8374 contains the byte that determines which keyboard device you want to select. The following values select for desired keyboard devices:
>00 Checks the entire keyboard. >01 Checks left side of keyboard and joystick #1. >02 Checks right side of keyboard and joystick 0@2
From the above table we see that if a value of >01 is placed at address >8374 the KSCAN routine will check for input from the left side of the keyboard as well as input from joystick #1. When a key is pressed its ASCII value is placed at address >8375. If no key was pressed this address will contain >FF. Lets
158
consider a program where input from the keyboard is used to perform some task. The following BASIC program will print a message on the screen based on which arrow key has been pressed. 100 110 120 140 160 180 190 200 CALL KEY (1,KEY,STATUS) IF STATUS=0 THEN 100 IF KEY=5 THEN A$="UP KEY PRESSED" IF KEY=3 THEN A$="RIGHT KEY PRESSED" IF KEY=0 THEN A$="DOWN KEY PRESSED" IF KEY=2 THEN A$="LEFT KEY PRESSED" DISPLAY AT (4,10):A$ GOTO 100
This program will display the "UP KEY PRESSED" message if the up 'E' key is pressed. If the 'D' key is pressed the "RIGHT KEY PRESSED' message appears. This continues on for the other two keys (X & S). The assembly language translation of this program illustrating the CALL KEY function is as follows: 001 002 003 004 005 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 *********************************************************** * CALL KEY (1,KEY,STATUS) * * This module will input from the arrow keys (E,D,X,S) * * and display a message indicating the pressed key. * *********************************************************** DEF * Reference needed utilities. BEGIN * Address to select keyboard REF KSCAN,VMBW * Holds ASCII # of pressed key KBOARD EQU >8374 >8375 KEY EQU * * * ASCII values KEYUP BYTE 5 of E, D, X and S * KEYRT BYTE 3 * keys KEYDN BYTE 0 * KEYLT BYTE 2 * No key pressed value HEXFF BYTE >FF * ONE BYTE 1 * TEXT 'UP KEY PRESSED ' UP RIGHT TEXT 'RIGHT KEY PRESSED' 'DOWN KEY PRESSED ' DOWN TEXT TEXT 'LEFT KEY PRESSED ' LEFT EVEN * MYREG BSS >20 * BEGIN LWPI MYREG MOVB @ONE,@KEYBOARD * Check left side of keyboard. * Check for keyboard input. BLWP @KSCAN LOOP @HEXFF,@KEY * Was a key pressed? CB * JEQ LOOP * Compare to see which CB @KEYUP,@KEY * arrow key was pressed. JEQ PUP
159
035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054
@KEYRT,OKEY PRIGHT @KEYDN,@KEY PDOWN @KEYLT,@KEY PLEFT @LOOP R1,UP @PRINT R1,RIGHT @PRINT R1,DOWN @PRINT R1,LEFT @PRINT R0,138 R2,17 @VMBW @LOOP
* * * * * * * * * * * * * * *
Pt L_. L_.
Jr DV
If you place a value of >01 at address >8374 the KSCAN routine will check for input from joystick #1 (as well as from the left side of the keyboard). If you place a value of >02 at address >8374 the KSCAN utility will check for input from joystick #2 (as well as from the right side of the keyboard). Input from joysticks is placed into CPU addresses >8376 (Y-position) and >8377 (X-position). Table 11.2 lists the possible values that may be returned.
>04 >FC
160
Lets assume that a value of >01 is at address >8374. Lets also assume that joystick #1 is in the DOWN-RIGHT position. When the KSCAN routine is called a value of -4 (:>FC) is placed at address >8376 and a value of 4 (>04) is placed at address >8377. The following xBASIC program will print out a message on the screen reporting on the current position of joystick #1. It is very similar to the CALL KEY program that was presented earlier.
100 110 120 130 140 150 160 170 180 190 200 210
CALL JOYST(1,JOYX,JOYY) IF JOYY=0 AND JOYX=0 THEN A$="CENTER" IF JOYY=4 AND JOYX=0 THEN A$="UP" IF JOYY=4 AND JOYX=4 THEN A$="UP-RIGHT" IF JOYY=0 AND JOYX=4 THEN A$="RIGHT" IF JOYY=-4 AND JOYX=4 THEN A$="DOWN-RIGHT" IF JOYY=-4 AND JOYX=0 THEN A$="DOWN" IF JOYY=-4 AND JOYX=-4 THEN A$="DOWN-LEFT" IF JOYY=0 AND JOYX=-4 THEN A$="LEFT" IF JOYY=4 AND JOYX=-4 THEN A$="UP-LEFT" DISPLAY AT(4,10):A$ GOTO 100
The above program will display a message on the screen reporting on the current position of joystick #1. The source code that follows is a direct translation of the previous xBASIC program. You may wish to study it in great detail as most game programs utilize a joystick input of one type or another.
*********************************************************** * CALL JOYST(1,JOYx,JOYY) * * This module will input from joystick #1 and display its * * * current position on the screen. ***********************************************************
009
010 *
DEF REF
START KSCAN,VMBW
161
011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061
KBOARD JOYY * JOYUP JOYUR JOYRT JOYDR JOYDN JOYDL JOYLT JOYUL JOYCT HEXFF ONE * UP UPRT RT DNRT DN DNLT LT UPLT CENTER EVEN * MYREG * BEGIN * START
EQU EQU BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT BSS LWPI MOVB BLWP C JEQ C JEQ C JEQ C JEQ C JEQ C JEQ C JEQ C JEQ LI B
>8374 >8376 4,0 4,4 0,4 -4,4 -4,0 -4,-4 0,-4 4,-4 0,0 :OFF 1
* Address of keyboard device select. * Joystick input "Y" value. * * * * * * * * * * * * * * .* * * * * JOYSTICK POSITION MESSAGES
* Reserve space for Workspace Registers. MYREG * Load pointer. @ONE,@KBOARD * Select keyboard device. @KSCAN @JOYY,@JOYUP P1 @JOYY,@JOYUR P2 @JOYY,@JOYRT P3 @JOYY,@JOYDR P4 @JOYY,@JOYDN P5 @JOYY,@JOYDL P6 @JOYY,@JOYLT P7 @JOYY,@JOYUL P8 R1,CENTER @PRINT * Scan joystick..
162
062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082
P1
P2 P3 P4 P5 P6 P7 P8 * PRINT
LI
B LI B LI B LI B LI
R1,UP
@PRINT R1,UPRT @PRINT R1,RT @PRINT R1,DNRT @PRINT R1,DN
*
* * * * * * * * Load appropriate message
B
LI B LI B LI LI LI BLWP B END
@PRINT
R1,DNLT @PRINT R1,LT @PRINT R1,UPLT R0,138 R2,10 @VMBW @START BEGIN
*
* * * * * * Display message on * screen. * * Return and check again.
ID I MI
BASIC is a powerful language when it comes to automatic string manipulation, array handling and specific error messages letting you know exactly where you went wrong. The price you pay for these luxuries is that the BASIC program will run very slowly when compared with assembly language. Because array management is not directly handled by the computer when using assembly language, you will have to set memory aside for that purpose. The best way to do this is through the use of the BSS and BES directives, either of these directives will set aside any amount of memory. Handling these 'chunks' is not too difficult, but it may help to use a pen and paper to keep track of your own arrays as you set them up in memory.
163
001 ******************************************************* * FOR DELAY=1 TO 1000 :: NEXT DELAY 003 * 005 ******************************************************* 006 . 007 . * For 1 R1,1 LI 008 * To 1000 R2,1000 LI 009 010 DELAY DEC R2 R1,R2 C 011 * Next Delay JNE DELAY 012 . 013 Of course this delay loop will execute much more quickly then its BASIC counterpart. In fact, unless you were looking for it you would probably not even notice this small of a delay! The maximum value we can one in the previous example we can create two registers the next example, the first then R2 clicks in to repeat "loops". 001 003 005 006 007 008 009 010 011 012 013 014 015 use in a single delay loop like the is 32767. To loop with larger numbers working together to keep count. In register counts down from 32767 and the count for a total delay of 98301
******************************************************* * FOR DELAY-1 TO 98301 :: NEXT DELAY * ******************************************************* . LI R2,3 LOOP1 LI R1,32767 * Load a count register. * Load maximum delay. LOOP2 DEC R1 JNE LOOP2 DEC R2 JEQ OUT JMP LOOP1 . OUT
Here we use R2 as our "second count" register and we use R1 as our "primary count" register. Line 009 is the beginning of our loop, R1 is loaded with the maximum signed value it can hold. The next line (010) decrements R1 by one and line 011 tests to see if R1 is zero yet. If not, the program jumps to LOOP2 and decrements R1 again. This continues until R1 is equal to zero, then R2 is decremented. If R2 has been decremented to zero program control jumps to OUT, otherwise the program jumps to LOOP1 and R1 is reloaded and the delay continues.
164
F- C3Fc-- NI E
X lr 9 -T
PI
For this instruction you just increment your counter register the amount of the step as demonstrated in the following source code: 001 003 005 006 007 008 009 010 011 012 ******************************************************* * FOR DELAY=0 TO 75 STEP 3 :: NEXT DELAY * ******************************************************* R1,0 LI DELAY INCT R1 R1 INC R1,75 CI JNE DELAY
Notice that lines 009 and 010 of the last example increment our count register (R1) a total of three for each pass of the DELAY loop. Take note that this source code could also be written:
0 0 M
008 LI R1,0 009 DELAY Al R1,3 010 CI R1,75 011 JNE DELAY Either version would work equally as well. For very large numbers we can again use two counter registers to keep track of things. Following our first example above we could translate the xBASIC statement FOR 1=10000 TO 0 STEP -1 into the source code: 001 ******************************************************** * 003 * FOR 1=10000 TO 0 STEP -2 :: NEXT I 005 ******************************************************** 006 . 007 . R2,10 008 LI 009 LOOP 1 LI R1,1000 010 LOOP2 DECT R1 JNE LOOP2 011 012 DEC R2 013 JNE LOOP1 Here we see R1 decremented by two after each loop. If you were using the value of "I" for some other procedure in the program you could get it simply by multiplying R1 and R2 together at any point during execution of these loops.
165
Conditional jumps and compare instructions constitute the primary computing structure in assembly language. It is fairly straight forward and can be easily demonstrated with a translation of the following:
001 003 005 . 008 009 . 200 201 202 203 204 205
********************************************************* * IF DAMAGE=100 THEN SHIP=10 * ********************************************************* DAMAGE SHIP . SUB1 DATA DATA . MOV CI JNE LI MOV RT >0000 >0000 @DAMAGE,R1 R1,100 OUT1 R1,10 R1,@SHIP * * If DAMAGE=100 * Then... . * * ..SHIP=10
OUT1
To add an ELSE to the statement you simply add three additional lines of source code as follows: 001 003 005 . 006 009 . 200 201 202 203 204 205 206 207 206 ******************************************************* * * IF DAMAGE=100 THEN SHIP=10 ELSE SHIP=5 ******************************************************* DAMAGE SHIP DATA DATA . MOV CI JNE LI MOV JMP LI MOV RT >0000 >0000 @DAMAGE,R1 R1,>64 ELSE1 R1,>A R1,@SHIP OUT1 R1,>5 R1,@SHIP
ELSE1 OUT1
DIN GC) B Ul Et In BASIC, you are limited with the GOSUB instruction to test very specific values before proceeding. For example:
100 ON Y GOSUB 200,230,240
166
performed with control returning to the statement just after the GOSUB after that one branch is finished. Also, if Y was not equal to any of the branches (ie: not=1, 2, or 3) an error message would be returned by the computer. Assembly language permits you much greater freedom in programming in that it permits multiply branch testing. In this situation, one, two or all the branches might be executed. Or alternatively, none of the branches may be branched to under certain conditions. The source code on the following page could be found in a game program where some value, perhaps inputed from the keyboard, determines which subprogram is branched to 001 003 004 006 007 008 009 010 011 012 013 014 015 016 017 018 ********************************************************* * * ON VALUE GOSUB 100,200,300 * Program module to perform a multiple branch test * ********************************************************* . . MOV @VALUE,R0 R0,100 CI * See if VALUE=100 JNE NEXT1 * If not, then jump to NEXT1 MISS BL * Branch & Link w/ MISS routine NEXT1 CI R0,200 * See if VALUE=200 NEXT2 JNE * If not, then jump to NEXT2 BL HIT * Branch & Link w/ HIT routine NEXT2 R0,300 CI * See if VALUE=300 JNE OUT * If not, jump to OUT BL KILLED * Branch & Link with KILLED
You will be BLing out of the program and RTing back to within the multiple branch test above to continue until all the branches have been tested. You will have to be careful that your subprograms MISS, HIT and KILLED do not change the value in RO or an accidental triggering of another branch may occur.
C3 INI B C) 11- C)
This is another version of the GOSUB structure we have just covered. The difference is that after one branch meets with a successful test, control jumps back to the point following all the branch tests. 001 002 003 004 005 007 010 011 ********************************************************** * ON GOTO * * This program module allows you to test branches one at * * a time. Program control transfers to a point following * * all branch tests after completion of a subroutine. * ********************************************************** . .
167
012 MOV @VALUE,R0 013 CI R0,100 014 JNE NEXT1 015 JMP SUBR1 * 016 NEXT1 CI R0,200 017 JNE NEXT2 018 JMP SUBR2 * 019 NEXT2 CI R0,300 020 JNE OUT * 021 JMP SUBR3 * 022 OUT Call subroutines "JMP" to location OUT when finished] Instead of RT, each subroutine in the last example will JMP back to location OUT, which lets the program continue without running through any more tests of the branches. In this way no branch is accidentally triggered if the subroutine were to change the contents of RO. REIM You can make notes directly inside program by preceding them with an asterisk (*). An entire line in a source program may be reserved in this way for comments or notes about your program. Comments also can be made after the operand field in most instructions by spacing once and typing in an asterisk (*) followed by your note or comment. The asterisk serves as a signal to the assembler to ignore the information you have typed. Your remarks remain part of the source code only and are omitted during the assembly process. FZIE -FL.IFP4 There are two return instructions in assembly language. They operate very similar to the way RETURN does in BASIC. THE RTWP takes you back from a subprogram to just after the BL (GOSUB) instruction that sent you to a subroutine. When a BL or BLWP instruction is reached, the address which immediately follows the BL or BLWP instruction itself is placed in R11. That address then stays in RII until a RT or RTWP is encountered. When this occurs, the address is taken from RII and placed into the Program Counter. This transfers program control back to the instruction just after the BL or BLWP line. FZ Ul IN If you are not going from BASIC to an assembly program, but are only running an assembly program by itself, there are basically two ways to run the program using the Editor/Assembler. The first way is to define an entry point with the DEF statement at the
168
beginning of the program. Using this method you load the object code into the computer using the LOAD and RUN option of the Editor/Assembler module. After the program is loaded you press ENTER and the PROGRAM NAME? prompt appears. You then type in the starting point of program. This entry must match a entry in the DEF statement at the beginning of the program. The second way to run a assembly language program is to place the entry point of the program in the operand field of an END directive. When this program is loaded it will start running automatically as soon as the file is loaded. The following illustrates these two methods of starting assembly programs: DEF START 001 . . . . . . 020 START . Using this procedure you must load the file that contains the object code with the LOAD and RUN option of the Editor/Assembler. When the file is loaded hit ENTER and the PROGRAM NAME? prompt appears. You then type in the entry point in your program which also must be found in a DEF statement at the beginning of the program. . 020 START . . . . END START 800 Placing the entry point to your program in the operand field of a END statement causes the program to start running automatically as soon as it is loaded with the LOAD and RUN option of the Editor/Assembler.
-169-
170
Both the Editor/Assembler module and the Mini Memory module provide you with several additional BASIC commands. These commands are designed to aid you in the task of interfacing your assembly language programs with BASIC. Table 12.0 outlines these commands.
Description
Initializes CPU memory for AL subroutines Load data or AL program into CPU RAM memory. Link BASIC program with AL program. Look at data in a CPU RAM address. Look at data in a VDP RAM address. Load data into VDP RAM. Return the value of a character pattern.
Each preceding BASIC command is discussed in detail in the sections that follow in this chapter.
This command must be called before any assembly language programs command are loaded through the BASIC program. This command should not be called once the assembly language program is loaded or the program will be rendered inaccessible. The CALL INIT command goes through the following procedures when called: 1. Check to see if memory expansion is connected to the console. Loads utility routines from the Editor/Assembler module into the memory expansion starting at address >2000. Loads the REF/DEF tables into the memory expansion at addresses >3F38 through >3FFF.
2.
3.
If you use the command CALL INIT 'with the mini memory module, all programs and data are erased. CALL INIT also initializes CPU RAM for assembly language subroutines and re-initializes the internal tables of the mini memory module. If memory expansion is attached, access is enabled to both the module and memory expansion. If the memory expansion is not connected or turned off, the memory expansion is not recognized. You do not need to use CALL INIT each time you use the module, since it has its own internal power supply. Remember that all data and programs on the
module are lost when you use the CALL INIT command!
171
LADicippItNilB
plEcalcir.
car>
To load an assembly language program (object code) you would use the following format of the CALL LOAD statement:
CALL LOAD("device.filename") where the device.filename is a string expression such as DSK1.FILE1. This file must be object code. You can load more than one object file at a time by separating the files you want by commas as in the following example: CALL LOAD("DSK1.FILE1","DSK1.FILE2")
which loads the two files FILE1 and FILE2 from disk drive 1. Relocatable object code is loaded at the first available address. With no files loaded and memory expansion attached this address is >A000. When using the mini memory module without the memory expansion unit attached this address is >7118, the lowest available address in the module's RAM. Subsequent programs are loaded in a sequential manner, with the next program loaded in memory immediately following the previous program. Absolute code is loaded at the absolute address specified by the object code. Your program should not use absolute code unless extreme care is taken, as loading data into an area of memory used by the TI BASIC interpreter can cause the computer to "crash".
-1PolKINie- EtplcrIA
To load or "poke" data into an area of CPU RAM you would use the following format of the CAll LOAD command:
CALL LOADtaddress,value)
where the address is a decimal number which can be any value from -32768 through 32767. Values 0 through 32767 represent addresses 0000 through 7FFF, while the values -32768 through -1 represent 8000 through FFFF expressed as two's compliment form. In order to find an address above 32767 you must subtract 65536 from it. You can load any number of bytes beginning at an address by specifying the values to load. For example, the statement:
CALL LOAD(-36864,24,13,90)
172
loads the values >18, >OD and >5A into the respective bytes at locations >7000, >7001 and >7002. You can specify more than one poke list by separating the last byte of one poke list and the starting address of the next poke list with a pair of quotes as in the next example CALL LOAD(-36864,24,13,",53248,19) which loads the same values as the preceding example and also loads the value >13 into address >D000. You could also load an assembly language program byte-by-byte in this manner by poking in the various instructions. However to run a machine language program loaded in this manner you would have to enter the program name and starting point into the REF/DEF table so that the computer could find it. You do not need to worry about these steps if your program was loaded by the Editor/Assembler loader since that is done for you. If you are using the Mini Memory Module you should use the procedure outlined on page 144. If you use xBASIC to run your assembly language program you must first perform the following steps: 1. Read the First Free Address in the Module with the CALL PEEK command. The FFAM can be found at address >2028. Read the Last Free Address in the Module. This address can be found at address >202A. Subtract the FFAM from the LFAM. If they differ by at least 8 bytes, there is room to add your program name and address. Use the CALL LOAD command to change the LFAM to a value 8 bytes less then its old value. Use the CALL LOAD command to load the program name (6 bytes in length) starting at the new LFAM followed by two bytes which give the program starting address.
2.
3.
4.
5.
For example, suppose the LFAM is >8000, your program name is FILE. The program begins at addess >8300. You would then load the following information:
173
IC ALL L_. I INA 1-c::: The CALL LINK command lets you pass control from a BASIC program to an already loaded assembly language program. It also lets you optionally pass a list of parameters from the BASIC program to the assembly language program. The format for the CALL LINK command is as follows:
CALL LINK("program-name","parameters...")
The program-name is a 1 to 6 character string that defines the entry point into the program. It must appear in the REF/DEF Table of the assembly language program that you are trying to link with. The assembly language program must already be in memory (loaded via the CALL LOAD command). The parameters are optional. They allow you to pass string variables, numeric variables, or expressions between your BASIC and assembly language programs. For example, the statement:
CALL LINK("BEGIN",A,D$)
passes control from a BASIC program to the assembly language program BEGIN, with the numeric variable 'A' and the string variable 'D$' passed to it. The CALL LINK command goes through the following operations when called: 1. Check to see if AL program name is 1 to 6 characters in length.
1.)
I... s
If name is right length, the name is looked up in the REF/DEF Table, beginning at the lowest address. The program name is then pushed onto the value stack. note: An error is generated if there are duplicate names in DEF instructions.
3.
If parameters are to be passed the utility will build an argument list. This list identifies the type of arguments and builds a stack entry for each argument. Program control is transferred to the assembly language program through a direct AL "branch" instruction.
4.
174
note: In order to return to your BASIC program, your AL program must preserve and restore the values in Workspace Registers R11, R13, R14, and R15 before ending. 5. At the end of the assembly language program, control will return to the calling BASIC program unless an error has occurred. If an error has occurred, the program branches to an error routine. note: Address >8310 contains the value stack pointer in use by BASIC interpreter. IRAFcrtnkrITEIR IPIABBING WITH iALL... LIINK
Up to 16 arguments can be passed between a BASIC program and an assembly language program. If the parameter is an expression, it is passed by its value, if it is a variable it is passed by name. Any variable except an expression can have its value changed by the assembly language program. This value, in turn, can be passed back to the BASIC program. You can pass entire arrays by enclosing them in parentheses. Arrays with more than one dimension are indicated by placing commas between the parentheses to indicate the number of dimensions. The following is an example outlining several simple variables (simple variables do not include expressions):
CALL LINK("BEGIN",A,B$,SCORE,F$0,0$(0) A = numeric variable B$ = string variable SCORE = numeric variable F$() = one-dimensional array G$(,) = two-dimensional array
If you need to pass variables to your assembly language program but do not need to change their values, surround the variable with parentheses. Arrays however, can not be passed in this manner. For instance, all but the last two in the last example can be passed without having their value changed on return to the calling BASIC program as outlined below:
CALL LINKOBEGIN",(A),(B$),(SCORE))
Also, constants such as SCORE-3, do not have their values changed by the assembly language program on return to BASIC. Arguments are passed to an assembly language through an identifier list in CPU RAM. It is not necessary for you to have a knowledge of how arguments are passed if you use the utilities described in section 13.1 If you want to delve deeper and
175
construct your own utilities, see pages 278-280 of your Editor/Assembler manual.
CALL PEEK(address,variable....)
where the address is a decimal number which can be any value from -32768 through 32767. Values 0 through 32767 represent addresses >0000 through >7FFF, while the values -32768 through -1 represent >8000 through >FFFF expressed as two's compliment form. In order to find an address above 32767 you must subtract 65360 from it. You can peek into any number of successive bytes of CPU RAM by simply specifying the variables. The following example illustrates how data can be read from CPU RAM:
CALL PEEK(-36864,A,B,C,D)
This statement lets 'A' represent the value held at address >7000, 'B' the value at address >7001, 'C' the value at address >7002 and 'C' the value at address >7003. You can read from more then one address in a single PEEK statement by separating the last variable of one PEEK list and the Beginning PEEK address of the next list with a pair of quotes. This is illustrated as follows:
The CALL PEEKV command is used to read bytes of data from VDP RAM. It works in exactly the same manner as the CALL PEEK command except that CALL PEEKV will read from VDP RAM. The format of the CALL PEEKV is the following:
CALL PEEKV(address,variable,var...)
The address is a decimal number which can range in value from 0 through 16383. The values 0 through 16383 represent addresses >0000 through >3FFF in VDP RAM. If you try to access a higher
176
address then >3FFF the system will crash requiring you to turn the power off and back on again in order to continue. The following example illustrates the use of the CALL PEEKV command:
The CALL POKEV command allows you to read bytes of VDP RAM directly into BASIC variables. It works in exactly the same manner as the CALL POKE command, except that CALLPOKEV will poke data into VDP RAM instead of CPU RAM. The format of the CALL POKEY command is as follows:
CALL POKEV(address,variable...)
where the address is a decimal number which can be any value from 0 through 16383. Values 0 through 16383 represent addresses >0000 through >3FFF. Keep in mind that VDP RAM only has 16K of memory. If you try to poke a value into an address higher than >3FFF, the system will crash requiring you to turn the console off and back on in order to continue. The following example:
CALL POKEV(300,32,32,32,"",5,SCORE)
places the value 32 (>20) in VDP RAM addresses 300 (>012C), 301 (>012D), and 302 (>012E). It also places the value of SCORE in VDP RAM address 5 (>0005).
IC ink L.. L_ IC HI Ink Fc Fs Pp 1-
The CALL CHARPAT command returns a 16-character pattern identifier that codes for the character specified by the character-code. The format of the CALL CHARPART command is as follows:
CALL CHARPAT(character-code,string-variable) where the character-code is any character number from 32 to 159. The pattern identifier codes for the ASCII character set normally occupy character codes 32 through 95, although you can redefine and can be defined through the use of the CALL CHAR command.
177
1p4=%Ftem-IIR F-ABBINie
Besides the additional BASIC commands provided, the Editor/Assembler and Mini Memory module also provide several assembly language utility programs that greatly simplify passing arguments between AL and BASIC. You can also return errors that occurred during execution of an assembly language module. Table 12.1 outlines these utilities. TABLE 12.1 BASIC INTERFACE UTILITIES UTILITY NUMSAG STRASG NUMREF STRREF ERR DESCRIPTION Number Assignment. String Assignment. Number Reference. String Reference. Error reporting,routine.
If you are using the Editor/Assembler these utility programs can be found on the disk labeled 'A' in the file named BSCSUP. They are in relocatable code and are about 900 bytes long. To use them you must include them in a REF statement at the beginning of your program. In order to load them you must place the statement:
CALL LOAD("DSK1.BSCSUP")
in your BASIC program. If you are using the Mini Memory module, the addresses of these utilities can be found on page 148.
Iolm
The values of variables passed from BASIC to assembly language programs are stored in the Floating Point Accumulator which begins at VDP RAM Address >834A. Before we progress to the utility programs proper, we must explain radix 100 notation. In radix 100 notation all numbers range from 1.000000000000 through 99.000000000000 multiplied by 100 raised to a power ranging from -64 to 64. Each number is coded for in an 8 byte "value stack" located in VDP RAM. The first byte in the value stack indicates the exponent of the numerical value. If the exponent is positive, the byte
178
value is 64 more than the exponent. If the exponent is negative, the byte value is gotten by subtracting 64 from the exponent. For example, if the exponent is 3, the byte is 67 or >43. If the exponent is -2, the byte is 62 or >3E. If the exponent is negative, the first two bytes are entered in two's-compliment form. After the exponent byte, the remaining seven bytes in the value stack contain the value of the number. No regard is given to the decimal point when transforming numbers into their hexadecimal equivalents. The second through eighth byte for a radix 100 value of:
3 100 x 23.456
is constructed as follows:
TABLE 13.2 EXAMPLES OF CONVERSION TO RADIX 100 NOTATION Decimal Value Radix 100 Notation o 6
60 1,234,560 12,345,600 0* -6 -6C) -1,234,560
Value Stack
6 x 100
o 60 x 100 1.23456 x 100 3 12.3456 x 100 o 0 x 100 o -6 x 100 o -60 x 100
'7
...)
>40 >06 >00 >00 >00 >00 >00 >00 >40 >3C >00 >00 >00 >00 >00 >00 >43 >01 >17 >2D >3C >00 >00 >00
>43 >0C >22 >38 >00 >00 >00 >00 >00 >00 >BF >XX >XX >XX >XX >XX >XX
>FA >00 >00 >00 >00 >00 >00 >00 >00 >00 >00 >00 >00 >17 >2D >3C >00 >00 >00
-1.23456 x
100
*Zero is expressed by >00 in the first two bytes & undefined in the remaining 6 bytes.
179
tNi
u rii IA B e
) tNi
u ri r3 a Ft
ALB I
e h4 hi la h4 ir
This utility allows you to assign a value to a variable passed as an arguement via the CALL LINK command of BASIC. Follow the steps outlined below in order to use this utility. 1. Place a value of 0 in RO if the variable is a simple variable. If the variable is an element in an array, place the element number in RO. Note: With OPTION BASE 0 (BASIC default) the array elements are numbered starting at O. If OPTION BASE 1 is selected the array elements are numbered starting at 1. Element numbers for multiple dimension arrays are found by counting through the first level, then the second level and so on. For example, an array defined as X(6,6 1 6) with an OPTION BASE of 0; element number X(3,2,1) is found: 2 1 0 (3 * 7 ) + (2 * 7 ) + (1 * 7 ) = 162 = element # 2. Place the arguement number as a full word in Rl. The arguement number is at it appears in the arguement list of the CALL LINK statement. Note: The arguement number is the order in which the arguement appears in the parameter list of the CALL LINK statement. For example, in the statement: CALL LINK("BEGIN",X,Y,Z) 'X' is arguement #1, 'Y' is arguement #2, and 'Z' is arguement #3 3. Enter the value you want to assign into the Floating Point Accumulator which begins at address >834A. The number must be in Radix 100 notation. Access the utility by BLWP @NUMASG using the Editor/Assembler or BLWP @6040 if you are using the Mini Memory Module.
4.
For example, the statement CALL LINK("FILE1",X,Y,Z) when encountered in BASIC would pass control to the assembly language program FILE1. If the Floating Point Accumulator beginning at address >834A contains >43 >02 >22 >38 >00 >00 >00 >00, RO contains >00 and R1 contains >02, then BLWP @NUMASG assigns 4.. ,-'4,5, 600 to 'Y'.
1.7
180
The following source code can be used to load a value into the FAC area: . . FAC EQU >834A VALUE BYTE >XX,>XX,>XX v >XX,>XX v >XX,>XX,>XX
.
C B ir FC Pr B CB ) B -11- FC I h4
This utility allows you to assign a string' to a string variable passed via BASIC command CALL LINK. Before using this utility you must: 1. 2. Create the string in CPU RAM with the first byte in the string indicating the length of the string. For simple string variables, place a value of 0 in RO. If you are assigning a string to an array; place the array element number in RO. Place the address of the string in R2. Place the arguement number as a full word in Rl. Access the utility with BLWP @STRASG if using the Editor/Assembler or BLWP @>6048 if you are using the Mini Memory Module.
3. 4. 5.
The example outlined below demonstrates the usage of the STRASG utility. The string "HELLO" is assigned to the string variable A* which is displayed on return to BASIC. 001 002 003 MESS 004 005 START 006 007 008 009 010 DEF START REF STRASG BYTE >05 TEXT 'HELLO' CLR LI LI BLWP @STRASG RT END
181
The following is the BASIC program that is needed. If you are using the Mini Memory module, omit line 20 as the program is already in memory. You would also need to change line 010 of the source code and omit lines 001 and 002.
10 20 30 40
2. 3.
The value of the variable will be returned in the Floating Point Accumulator area starting at address >834A. The number will be in Radix 100 notation.
P<EMICE
This utility allows you to get a string that was passed via CALL LINK command from BASIC. You must reserve an area of memory to hold the string before calling this utility. The following steps outline how this accomplished: 1. Reserve a buffer area in memory to hold the string. The first byte of the buffer area should hold the length of the string. If the the string length actually exceeds this value, an error is generated. Otherwise the actual length is placed in the first byte. Place 0 in RO if it is a simple string variable. Place the element number if the string is in an array. Load the starting address of the buffer in R2. Call the utility.
2.
3. 4.
182
la IR Fc C) Fc Pc la IF- C3 Fc -r I rq e
This utility allows you to transfer control to the error reporting routine in BASIC. To use this utility all you have to do is load the error code into the most significant byte of RO and call the utility via BLWP @ERR or BLWP @6050. The error codes that can be listed by your program are found in Table 13.3 on the adjacent page.
ERROR MESSAGE
error (bad name) I/0 error (write protected) I/0 error (bad attribute) I/O error (illegal operation) I/0 error (buffer full) I/0 error (read past EOF) I/0 error (device error) I/0 error (file error) Memory full (closes file) N/A Bad tag Checksum error Duplicate definition Unresolved references N/A Program not found Incorrect statement Bad name Can't continue Bad value
I/O
Along with the many utilities discussed in Chapter 6, there are many additional utility programs related to mathematics that literally save you hours (or days) in programming time. The first section of this chapter outlines mathematical GPL routines that can be accessed through GPLLNK. The second section of this chapter discusses ROM console routines that can be accessed through XMLLNK.
-183-
184
All of the following routines involve floating point numbers. If an error occurs during execution of the routine, the error is indicated in byte >8345. Table 13.0 gives all the possible error codes that can be returned.
ERROR TYPE
Overflow. Syntax error. Integer overflow on conversion. Square root of a negative number. Negative number to non-integer power. Logarithm of a non-positive number. Invalid argument in trigonometric fxn.
Table 13.1 outlines the mathematical routines that can be accessed through GPLLNK.
DESCRIPTION
Convert number to string. Greatest integer function. Involution routine. Square root routine. Exponent routine. Natural logarithm routine. Cosine routine. Sine routine Tangent routine. Arctangent.
>0032
The sections that follow in this chapter describe the GPL mathematical routines. The address of the Floating Point Accumulator is >834A. The Floating Point Accumulator is abbreviated FAC in the following sections.
Parentheses indicates the BASIC statement which would call the routine from a BASIC program.
185
This routine allows you to convert a floating point number into a ASCII string. The following are the necessary steps: 1. The eight bytes defining the number are located beginning at FAC. If you set FAC+11 (>8355) equal to zero, it indicates that the output string is to be in BASIC format. Otherwise the output is in FIX mode, which requires data in FAC+12 and FAC+13 (>8356 & >8357). FAC+12 is the number of significant bytes. If 1, it expresses overflow from the calculation range. FAC+13 indicates the number of digits to the right of the decimal point. A negative value disables the FIX mode. 3. After the execution of the STR routine, FAC is modified. FAC+11 (>8355) contains the least significant byte of the address where the string is located. This byte must be added to >8300 to find the actual address of the string; address=(FAC+11)+>8300. FAC+12 (>8356) contains the length of the string (in bytes).
2.
DATA >0022 [INT] GREATEST INTEGER FUNCTION This routine allows you to compute the greatest integer contained in a value. 1. 2. FAC contains the floating point value. After calling this routine, FAC contains the result. For positive numbers, the integer is the truncated value. For negative numbers, the integer is the truncated value plus one. The GPL status byte (>837C) is set according to the result.
3.
DATA >0024 INVOLUTION ROUTINE This routine allows you to raise a number to a specified power. 1. 2. FAC contains the exponent value. Address >836E (STACK) contains the address in VDP RAM that holds the eight byte number.
186
3. 4.
The result is placed in FAC in floating-point format. This is computed as exp*LOGEABS(base)3. After completion of this routine, the data at addresses >8375 and >8376 is destroyed. The word at address >836E is decremented by 8.
DATA >0026 ESQR3 SQUARE ROOT ROUTINE This routine allows you to find the square root of a number. 1. 2. 3. 4. FAC contains the input value. After the routine, FAC contains the square root of the input value. The GPL status byte is affected. Addresses >8375 and >8376 are destroyed by this routine.
DATA >0028 [EXP3 EXPONENT ROUTINE This routine will compute the inverse natural logarithm of a number. 1. 2. 3. 4. FAC contains the input value. After the routine, FAC contains the resulting value. The GPL status byte is affected. Addresses >8375 and >8376 are destroyed by this routine.
DATA >002A CLOG] NATURAL LOGARITHM ROUTINE This routine will compute the natural logarithm of a number. 1. 2. 3. 4. FAC contains the input value. After the routine, FAC contains the resulting value. The GPL status byte is affected. Addresses >8375 and >8376 are destroyed by this routine.
187
This routine will compute the cosine of a number that is expressed in radians.
1. 2.
FAC contains the input value. After the routine, FAC contains the cosine of the input value. The GPL status byte is affected. Addresses >8375 and >8376 are destroyed by this routine.
3. 4.
3. 4.
DATA
>0030
This routine Oill compute the tangent of a number expressed in radians. 1. 2. FAC contains the input value. After the routine, FAC contains the tangent of the input value. The GPL status byte is affected. Addresses >8375 and >8376 are destroyed by this routine.
3. 4.
DATA
>0032
This routine will compute the arctangent of a number expressed in radians. 1. FAC contains the input value.
188
2.
After the routine, FAC contains the arctangent off the input value.
3.
4.
To review how to call up GPL routines through the use of the GPLLNK utility, refer to page 82 of chapter 6. Remember that you must reset the GPL status byte at address >837C, or a meaningless error message will be returned. Also make sure that any of the CPU RAM areas that are affected by a GPL routine are not being used by your program to store information. The addresses that you need to use these utilities with the mini memory module can be found in table 10.1 on page 148. Routines that are located in ROM can be accessed through the use of the XMLLNK command. There are two ways to access a routine in console ROM. The first is to specify the routine's code in a DATA statement. For example,
BLWP @XMLLNK * 8 D 3 A (note MSB set to indicate DATA >8D3A * 1000 1101 0011 1010 an address)
branches to console ROM address >0D3A which is the floating point compare routine. Unless absolutely unavoidable, you should not use direct memory addresses of console ROM routines as they can vary from one console to another. Table 13.2 outlines the console routine codes that can be used with XMLLNK.
189
Description
Floating-Point Addition Floating-Point Subtraction Floating-Point Multiplication Floating-Point Division Floating-Point Compare Operation Floating-Point Stack Addition Floating-Point Stack Subtraction Floating-Point Stack Multiplication Floating-Point Stack Division Floating-Point Stack Comparison Convert String to Number Convert Floating-Point to Integer Push a value onto Value Stack Pop a Value for the Value Stack Convert Integer to Floating-Point
In the routines that follow, FAC starts at address >834A, ARG (which stands for arguments) starts at address >835C. STACK is at address >836E. All overflow errors, except in convert floating point to integer, return >01 at address >8354.
DATA
>0700
3.
190
DATA
>0900
2. 3.
ARG holds the dividend. FAC holds the result of the operation after calling the utility.
DATA
>0A00
This routine compares two floating point numbers. 1. FAC holds the first number while ARG holds the second. The GPL status byte (>837C) is affected. The high bit is set if ARG is logically higher than FAC. The greater than bit is set if ARG is arithmetically higher than FAC. The equal bit is set if ARG and FAC are equal.
2.
DATA
>0B00
This routine will add using a stack in VDP RAM. 1. STACK contains the VDP RAM address where the left-hand term is located. FAC holds the right-hand term. FAC holds the result of the addition after the addition after the routine is called.
2. 3.
191
DATA >0D00
This routine will multiply using a stack in VDP RAM. 1. 2. 3. Stack contains the VDP RAM address of the multiplicand. FAC contains the multiplier. FAC holds the result of the multiplication after the routine has been called.
STACK contains the VDP RAM address holds the dividend. FAC holds the divisor value. FAC holds the result of the division after the routine has been called.
,
4.
This routine will compare a value in the VDP RAM stack to the value in FAC. 1. 2. STACK holds the VDP RAM address of the value to be compared. FAC holds the other value to be compared.
192
3. The GPL status byte (>837C) is affected. The high bit is set if STACK is logically higher than FAC. The greater than bit is set if STACK is arithmetically higher than FAC. The equal bit is set if STACK and FAC are equal.
DATA >1000 CONVERT STRING TO NUMBER This routine will convert an ASCII string into a floating-point number. 1. FAC+12 (>8356) is the address of the starting in VDP RAM. 2. FAC holds the result of the conversion in floatingpoint format.
DATA >1200 CONVERT FLOATING POINT TO INTEGER This routine will convert a floating-point number into an integer. 1. 2. FAC contains the floating-point number to be converted. FAC will contain integer value as one word. The maximum value of this word is >FFFF. If there is an overflow, FAC+10 (>8354) is set to the overflow error code, >03.
DATA >1700 PUSH VALUE ONTO VALUE STACK This routine will push a value you have loaded in FAC onto the value stack.
DATA >1800 POP VALUE FROM VALUE STACK This routine will pop a value from the value stack and place it in FAC.
193
1.
FAC contains the one-word integer that is to be converted. FAC will contain the floating-point result after the routine is called.
2.
NOTE: This routine is only available with the Editor/Assembler and is not supported in Extended Basic or by the Line-by-Line assembler. It has also been found that the correct code for this routine may be >7200 in some consoles.
I NDEX
A (add words) AB (add bytes) 36 37 ABS (absolute value) 37 Absolute value Absolute code 66,140 Absolute origin 66 Accept tone 84 Add bytes 36 Add immediate 37 Add words 36 Addressing modes Addressing immediate 26 indexed memory 28 program counter relative 29 symbolic memory 28 Workspace Register 26 Workspace Register indirect auto-increment Add immediate 37 ANDI 51 AORG 66,140 Arctangent routine 187 Arguement passing 174 Arithmetic instructions .. 29,35 Assembler directives 65 Assembler output 74 Branch & link Branch & load Workspace pointer Branch instruction BSCSUP BSS BYTE Byte structure 43 43 43 169 67 70 6
B
Bad response tone BASIC linkage BASIC support utilities BES Binary numbering system Bit reversal routine BIT-MAP MODE BIT-MAP MODE example BL Block ending with symbol Block starting with symbol BLWP
C 47 CALL CHARPAT 176 CALL INIT 170 CALL LINK 173 CALL LOAD 171 CALL PEEK 175 CALL PEEKV 175 176 CALL POKEV Cassette DSR routine 85 CB 48 CI 49 Clear instruction 54 CLOSE PAB opcode 89 CLR 54 COC 49 103,119 Color codes Color table BIT-MAP MODE 107 101 GRAPHICS MODE Comment field 23 48 Compare bytes 49 Compare immediate 46 Compare instructions Compare ones corresponding instruction 49 47 Compare words Compare zeros corresponding 49 instruction Constant initialization 21 Constants assembly-time 21,69 character 21
196
INDEX
decimal hexadecimal Controller access, sound ... Covert floating to integer Convert integer to floating point Convert number to string Convert string to number Copy command COPY Cosine routine CZC
END 73 Entry points 72 EQU 21,69 Equates 21,69 ERR reporting utility 93 Error codes that can be returned ..... 182,184 EVEN 68 External definition 72 External reference 72
F7
Field comment label operand operation code File characteristics File defaults File specification File type Floating point addition . Floating point compare .. Floating point division Floating point multiplication Floating point subtraction Frequencies, sound 23 22 27 86 93 86 86 189 190 190 189 189 130
DATA 70 Data initialization 70 DEC Decimal to Hexadecimal interconversions 12 Decrement by two Decrement 37 DECT 38 DEF 72 DEF/REF table 72 Define assembly time constant 21,69 Define extended operation ... 73 DELETE PAB opcode 89 Device service routine 85 Directives that affect assembler output 74 Directives that affect location counter 66 Directives that initialize constants 69 Directives that link programs 71 Directives, assembler 65 Directives, miscellaneous . 73 DISPLAY, file type 87 DIV 38 DORG 67 DSR 85 DSRLNK 85 Dummy origin directive 67 Duration control, sound .... 132 DXOP 73 EE Editor 20
C3
General addressing modes Get string space GPL routines GPLLNK Graphics GRAPHICS MODE
25
84 83 82 97 101
EA
Hexadecimal system Hexadecimal to decimal conversions 5,11 12
IDT Immediate addressing INC Increment by two Increment INCT Indexed memory addressing
75 26 29 40 40 28
INDEX
197
INIT Initialize byte Initialize text Initialize word INPUT PAB opcode Instructions by group arithmetic branch compare control jump load and move logical shift Interrupt handling INV Involution routine
170 70 71 70 87
,:, ..J
IL_
22 Label field LI 33 LIMI 34 LINK subroutine 173 Load immediate value 33 34 Load interrupt mask Load lower case character set 85 LOAD PAB op-code 89 Load small captitals character set 84 Load standard character 83 set Load Workspace pointer immediate 74 Location counter directives 66 Logical instructions 50 LWPI "1. 4 Ni Maginfication of sprites 120 Mathematical routines ... 183 Memory-mapped devices 77 Miscellaneous directives 73 Mnemonic codes 23 ") I:::" Modes, addressing .e......1 MOV "7 7 MOVES 33 Move command MPY 40 106 MULTICOLOR MODE Multiply instruction 40
1 ...T., .1 s 'II ....)
-7=
42 46 42 42 -.V? 50 57 34 54 185
0
JED JGT JH JHE JL JLE JLT JMP JNC JNE JNO JOC JOP Joystick use Jump if equal Jump if greater than Jump if high or equal Jump if less than Jump if logical high Jump if logical low Jump if low or equal Jump if no carry Jump if no overflow Jump if not equal Jump if odd parity Jump instructions Jump on carry li< KSCAN 42 42 42 42 42 42 42 44 42 42 42 42 42 159 42 42 42 42 42 42 42 42 42 42 42 42 42
P4
Natural logarithm routine routine 186 NEG 41 8 Negative numbers No operation 61 75 No source list Noise specification byte 129 for sound 61 NOF' 179 NUMASG Numbering systems 181 NUMREF D Object code OPEN PAB op-code
....
80 15 87
198
INDEX
Operand field ORI OUTPUT PAB op-code F.:" PAB PAGE directive Page title directive Pattern descriptor table BIT-MAP MODE GRAPHICS MODE MULTICOLOR MODE PEEK subroutine PEEKV subroutine Periodic noise Peripheral access block .... POKEV subroutine Predefined symbols Program counter register Program counter relative addressing Program organization Pseudo-instructions
27 51 87
44 146
ca
Quit key, interrupts 34 FR READ PAB op-code 89 REF (external reference) 72 REF/DEF 72,144 Registers 16 Registers, VDP 98 Relocatable object code 67 RESTORE/REWIND PAB op-code 89 Return pseudo-instruction 62 Return Workspace pointer 44 Returning 62 Roll-up 143 Roll-down 143 16 ROM ROM routines 82,183 RORG 67 Routines GPL 82 mathematical 183 ROM 183 RT 62
E3 SAVE PAB op-code 90 41 SB Screen image table BIT-MAP MODE 107 GRAPHICS MODE 102 MULTICOLOR MODE 106 TEXT MODE 107 m...... Set ones corresponding . ,J,..) 54 Set to one ic. ... J., Set zeros corresponding Set zeros corresponding == byte ,J,J SETO 54 57 Shift instructions Shift left arithmetic 57 57 Shift right arithmetic Shift right circular 60 Shift right logical 59 Sine routine 187 120 Size of sprites SLA 57 SOC 55 == SOCB ,J,J Sound 127 Sound, duration control . 128 Sound, frequency 130 Sound, noise 132 Sound, table 128 Source listing 20 Source statement 20,22 115 Sprites Sprite attribute list ... 116 Sprite descriptor table . 116 Sprite magnification .... 120 116 Sprite motion table Sprite size 120 Square root routine 186 SRA 57 SRC 60 SRL 59 STATUS byte 17 STATUS PAB op-code 90 Status Register 17 Status Register bits affected 18
INDEX
199
Store status Store Workspace pointer STRASG STRREF STST STWP Subtract bytes Swap bytes SWPB Symbolic memory addressing SZC SZCB
34 34 180 181 34 41 34 34 28 56 56
Workspace Register indirect addressing Workspace Register indirect autoincrement addressing Workspace Register shift instructions WRITE PAB op-code
27 27 57 89
x
X XMLLNK XOP XOR 46 188 31 51
ir
Tangent routine 187 Terms 21 TEXT 71 TEXT MODE 107 TITL directive 75 Two's compliment notation . 8
Li
Unconditional jumps UNL UPDATE PAB op-code Utilities 44 75 87 77
Value stack addition Value stack compare Value stack division Value stack multiplica Value stack subtraction VDP access VDP write only Registers VMBR VMBW VSBR VSBW VWTR
White noise 132 Word boundry 10 Word organization 10 Workspace 16 Workspace pointer Register 17 Workspace Register addressing 26
APPENDIX A
201
IA IF Fft
Nap I
ink
HEXADECIMAL/DECIMAL INTERCONVERSIONS 6 DEC ! !O !1 !2 !3 !4 15 !6 !7 !8 !9 !A !B !C !O !E !F ! !HX! 5 ! DEC !HX! 0!0 65,536!1 131,072!2 196,608!3 262,144!4 327,680!5 393,216!6 458,752!7 524,288!8 589,824!9 655,360!A 720,896!B 786,432!C 851,968!D 917,504!E 983,040!F DEC=decimal
4
DEC
! !H X !
3 DEC
! !HX!
! ! DEC!HX!DEC! ! 0!0 16!1 32!2 48!3 64!4 80!5 96!6 112!7 128!8 144!9 160!A 176!B 192!C 208!D 224!E 240!F 0! 1! 2! 3! 4! 5! 6! 7! 8! 9! 10! 11! 12! 13! 14! 15!
0!0 1,048,576!1 2,097,152!2 3,145,728!3 4,194,304!4 5,242,880!5 6,291,456!6 7,340,032!7 8,388,608!8 9,437,184!9 10,485,760!A 11,534,336!B 12,582,912!C 13,631,488!D 14,680,064!E 15,728,640!F
0!0 4,096!1 8,192!2 12,288!3 16,384!4 20,480!5 24,576!6 28,672!7 32,768!8 36,864!9 40,960!A 45,056!B 49,152!C 53,248!D 57,344!E 61,440!F
0!0 256!1 512!2 768!3 1,024!4 1,280!5 1,536!6 1,792!7 2,048!8 2,304!9 2,560!A 2,816!B 3,072!C 3,328!0 3,584!E 3,840!F
HX=hexadecimal
POWERS OF 2
x
POWERS OF 16
x x
2 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16,384 32,768 65,536 131,072
16 1 16
256 4,096 65,536 1,048,576 16,777,216 268,435,456 4,294,967,296 68,719,476,736 1,099,511,627,776 17,592,186,044,416 281,474,976,710,656 4,503,599,627,370,496 72,057,594,037,927,936 1,152,921,504,606,846,976
0 1 2 3 4 5 6 7
0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
a
9 10 11 12 13 14 15 16 17
202 APPENDIX
se%
IF" Fa E. IN/I ID I X Ec
11 11111 11 11 11
0 -C 4-3
CO O ,C 3-4 Hi 3 0) m
11111
11111
11 W
a)T1a/
,Q C 344 IC Q. 41i 0.4 H>4 It E 3-4 to 4-4 0-4 344 $4 JO CO-1 4:0
x
0C > O O
11
II
111111
III
!XIII
11
IX1111
111
XXXX I XXIX!
1 1
11 II
111111 111111
XXX XXI
TMS 9900INSTRUCTIONSETSUMMARY
E O CV 01
- I-10)01
a
A
XX X XX
I I I
XXXIXX
XXI
a) a) -rt C ,Q
0 01 4) %--'0 co l/ to .0 TS 0)
W C
ro .0 Ei
THE TMS9900INSTRUCTI ON
XXXXX
I 1 1
X X X 1 I 1
XXI
X X X X X
1 1 i
X X X i 1 1
X X i
O
Z
4.1
TI 4-)
4P CO LI 0 0 Hi W 4 0) N X
1-10
N N ca 3 0-1 a) 0 4-) C
07 a.
4-/
E
U
N
V to C 4:-)
co E
L
a
1Js
(i (J
r,
- 000 001t1033 00 0 0 3: 0 O
LO O
C7
ra C O1 u) a.)
04
4,4
as 4-7 o o i ww C
CD rC
44-4
U
0
E
X
a_
F-
203
1 I
1 1
1 I
1 1
1 1
1 I I
I
1
I
l
I
1 1
1 1
1 I 1
I
1 1 1
I
i i i
1
I 1 1
1
i
1
tn
I 4-3
1 1 1
1 I
I
1 I
I
I 1
I
1 1
I
I I
I
X X
x
1 I
I
III I 1 1
I
1
1
1
I
1
1
1
I
1
1
1
i
1
1
1
i I
O O
Ill
1111114-3
11
(c on t inu e d )
X X
X X
1
I
1111
1111
11114J1
1 1 4-3 1 1 4
1
1
11
1 I
1
1
1
I
X
I
I
1
X X X
1 4-3 1
X X i
x i
xxx
14-311114-311
1i
x I
xx I
x I
Icn
A
-J xxx 1144441111 1 I x I xx I x I x
Ill 0) a..
01 0 (r) Cr Li)
(r) Cr Cr (r)
el 0 (r) (r) Cr
0 Cr LD
I-
I
4J
(U
E
L
0
0 0 0
Ii
E EEEEEEEEEEEE O 000000000000 r-i r-i -r-ir-i r.1 r-i r-1 -r-i r-i r-i (11 (11 (11 (1) (11 111 (11 (11 (11 (1) (11 (11 111 (1) (1) (11 (1) (1) (1) (1) (1) 111 (1) (1) (1) CU CU CU CU CU CU CU CU CU CU CU CD CU L LLLLLLLLLLLL
# 3
1-7 0 3
f-,
3 ID CD CD
CL O. CL CL CL CL CL CL 0_ CL CL CL 0_ XXXXXXXXXXXXX Ill CD U) U) U) U) U) U) U) U) U) U) U)
E
II)
1.--i 1.--i 03 1DU> 0 IL 1.--1 0' 1W 1111-1:LOWOUIL > > >I a. ZZZ WOMI_J-J_JZZZZOO 1-'1-'3 0011 WO CC )--11-11-1 _J_J_J :EXM ZZ 0
204
APPENDIX B
X IA CO M 4-3 C
H
I I I 1
I I I I
I I I I
I I I
I
I I
1 1
I I I 1
I I I I
1 1 1 1
X X X
X
x
X X
V l 1 I I
1 l 1
1 I
I
I I
I
I 1
I
I 1
I
V I 1
co -4 w (co n t inu e d)
N 0)
a. o
Ill 3
4J CO 4-3
> o
LJ
X
X
XXI
I I
I I I
I I
X I X I
I I
X X i X I
I X X X I
U)
w A <
A -J
X X I XXX X X X 1 I I XX
X I X
X X i XXX X X X 1 I I XX
X I X
X X I X X X X X X I I I XX
X I X
CU 'Ct CO 'Ct
N n- 'Ct N cl* ID N Cr) Cr) q '1 in in LO 'Ct 'Ct LI) 1.f) in in in cn in PI PI PI lf) lf)
LO N 0 'Ct PI LI)
uJ
I I4J CO E L 0 IL CD CD - L7 CDO t....... %....., co ,---, co %....., ,---, ,---, ,---, 3 3 0 t--, t....... ... ... 3 - 3 3 3 co Lo t....., 0 t...... t....... t....... CD 0 33 ,....... ... ... 0 ID
,.....,
0 ,-i C 0 E CD C X
a.
co
I < U LJ < _1 U CO 3 0_ 0
1-
EL CO
GO C.) CL CC
I I-CC CC
0 0
X X X
205
The following table summarizes the Editor/Assembler director set. These directives are in alphabetical order. For each directive is shown the general assembler format. The page number given refers to where in the book the directive is described, parentheses indicate where the directive is described when referring to source code created using the mini memory module.
exp,exp...expression 70(138) symbol,symbol...symbol 72 expression 67 Symbol expression 73(141) 69(138) 68 74 74 75 72 67 (139) 71(138) 75 74 73
APPENDIX D
207
10 20 30 40 50 60
Notice that the source code listing for the same program is much longer. This allows you much greater flexability, but the price is much more time spent programming.
DEF REF * JOY1 JOY2 JOY3 JOY4 JOY5 JOY6 JOY7 JOYS ONE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE EVEN
SPRITE VMBW,VWTR,KSCAN 4,0 4,4 0,4 -4,4 -4,0 -4,-4 0,-4 4,-4 1
* JOYY EQU >8376 KBOARD EQU >8374 NUMB EQU >837A SATAB EQU >0300 SDTAB EQU >0400 SMTAB EQU >0780 * BALL DATA >3C7E,>FFFF,>FFFF,>7E3C SDATA DATA >70D0,>8008 DATA >D000 * SPO DATA >0000,'>0000 *
208
APPEND I X D
MYREG BSS >20 SPRITE LWP I MYREG LI RO , SDTAB LI R1 , BALL LI R2 , 8 BLWP @VMBW LI RO , SATAB LI R1 , SDATA R2 , 8 LI BLWP @VMBW LI R1 , 1 SLA R1 , 8 MOVB R1 , @NUMB LI RO , >0701 BLWP @VWTR MOVB @ONE , @KBOARD
* * *
* LOOP
LI RO , SMTAB LI R1 ,SPO LI R2 , 4 BLWP @VMBW LIMI 2 LIMI 0 BLWP @K SCAN MOV @JOYY , @JOYY JEQ LOOP C JEQ C JEQ C JEQ C JEQ C JEQ C JEQ C JED @JOYY , @JOY1 M1 @JOYY , @JOY2 M2 @jOYY , @JOY3 M3 @JOYY , @JOY4 M4 @JOYY , @JOY5 115 @JOYY , @JOY6 M6 @JOYY , @JOY7 M7
* LOOP1
APPENDIX D
209
M1 M2 M3 M4 M5 M6
LI B LI B LI B LI B LI B LI B LI B LI
R1,JOY6 @CHANGE R1,JOY5 @CHANGE R1,JOY4 @CHANGE R1,JOY3 @CHANGE R1,JOY2 @CHANGE R1,JOY1 @CHANGE R1,JOY8 @CHANGE R1,JOY7
B END
@LOOP1
The last program worked well enough but it went about it the long way around. Using a little ingenuity we can considerably shorthen the above program. The source listing that follows accomplishes the same task as the last program, only it has been shortened with some programming tricks.
DEF SPRITE REF VMBW,VWTR,KSCAN * ONE BYTE 1 ZERO BYTE 2 * JOYY EQU >8376 KBOARD EQU >8374 NUMB EQU >837A SATAB EQU >0300 SDTAB EQU >0400 SMTAB EQU >0780 * BALL DATA >3C7E,>FFFF,>FFFF,>7E3C SDATA DATA >70D0,>8008 DATA >0000 * SPO DATA >0000,>0000 *
210
APPEND I D
>20 MYREG BSS SPRITE LWP I MYREG RO SDTAB LI R1 , BALL LI R2 , 8 LI BLWP @VMBW
*
LI RC) , SATAB LI R1 SDATA LI R2 , BLWP @VMBW
*
LI R,1 R , SLA MOVB R1 , @NUMB
*
LOOP LI R0,SMTAB R1 ,SF'0 LI R2 , 4 LI BLWP @VMBW LIMI LIMI 0 BLWP MOV @JOYY @JOYY JEO LOOP CB @JOYY , @ZERO JEO GO MOVB @J 0Y+ 1 , @R5 NEG @JOYY MOVB R5 @JOYY+ 1 LI R1 , JOYY JMF' CHANGE
*
LOOP 1
*
GO LI R1 JOYY RO SMTAB CHANGE LI LI R2 ,2 BLWP @VMBW * B @LOOP 1 END
APPENDIX D
211
The last two programs can be loaded via the LOAD AND RUN option of the Editor/Assembler and run by typing in SPRITE in response to the PROGRAM NAME? prompt. In order to run these programs using the Mini Memory module you must: 1. 2. 3. Alter the length of all LABEL fields to two characters. Use appropriate address instead of symbols for the utility programs. Enter the program name and starting point into the REF/DEF table (refer to page 145).
The third program in this series illustrates additive motion. The longer you hold the joystick in one direction, the faster your sprite will move (here a red ball again!) To stop the sprite you will have to cancel out the motion by holding the joystick in the opposite direction to "brake" the sprite. This module lends itself well to incorporation of "space games" where you have to simulate the abscence of gravity.
10 20 30 40 50 60 70 80
CALL CLEAR CALL SCREEN(2) CALL CHAR(128,"3C7EFFFFFFFF7E3C") CALL SPRITE(#1,128,9,100,100) CALL JOYST(1,C,R) X=(X+C)*-(ABS(X)<124) Y=(1-R)*-(ABS(Y)<124) CALL MOTION(#1,Y,X)
NOTE: A direct translation of line 60 is: IF THE ABSOLUTE VALUE OF X<124 THEN X=X+C ELSE X=0 The following program is the assembly language version of the above program. Note how the "CALL SCREEN" code was added. DEF SPRITE REF VMBW,VWTR,KSCAN,VSBW * JOY1 JOY2 JOYS J0Y4 J0Y5 JOY6 JOY7 JOYS ONE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE EVEN 4,0 4,4 0,4 -4,4 -4,0 -4,-4 0,-4 4,-4 1
212
APPENDIX D
>8376 >8374 >837A >0384 >0300 >0400 >0780 >3C7E >70D008008 >D000 >0000,>0000 >1000
*
BALL DATA SDATA DATA DATA SPEED DATA COLOR DATA
SPRITE LWPI MYREG LI RO,COLTAB MOV @COLOR,R1 BLWP @VSBW CLR LI LI BLWP INC DEC JGT RO 5102000 52,767 @VSBW RO 52 LOOP
LOOP
*
LI 5000701 BLWP @VWTR LI RO,SATAB R1,SDATA LI LI R2,8 BLWP @VMBW LI RO,SDTAB LI R1,BALL LI R2,8 BLWP @VMBW 51,1 LI SLA R1,8 MOVB R1,@NUMB
*
MOVB @ONE,@KBOARD RO,SMTAB LI LI R1,SPEED Rd, 4 LI BLWP @VMBW
`,
APPED I X D LOOP1 LIMI 2 LIMI 0 BLWP @KSCAN MOV @JOYY , @JOYY LOOP1 JEQ @JOYY ,@JOY1 C JEQ UP @JOYY , @JOY3 C RIGHT JEQ @JOYY , @JOY5 C JEQ DOWN C @JOYY , @JOY7 JEQ LEFT @JOYY , @JOY2 C JEQ UPRT @JOYY , @JOY4 C JEQ DNRT @JOYY , @JOY6 C JEQ DNLT C @JOYY , @JOYS JEQ UPLT JMP LOOP1 UP UPRT DECT R5 @ADJUST B DECT R5 INCT R6 B @ADJUST I NCT R6 B @ADJUST INCT R5 INCT R6 B @ADJUST INCT R5 @ADJUST B INCT R5 DECT R6 B @ADJUST DECT R6 B @ADJUST DECT R5 DECT R6
213
RIGHT DNRT
DOWN DNLT
LEFT UPLT
214
APPENDIX D
This next program will illustrate the double-size and m,agnified sprite concept. When the program is run the sprite (a red ball) is standard sized and in motion across the screen. When any key is pressed the sprite is doublesized. When a key is pressed again the sprite is magnified. Finally, a third press of a key will make the sprite double-sized and magnified. Subsequent pressings of a key will repeat the cycle. DEF REF SPRITE VMBW,VSBR,VSBW,KSCAN,VWTR
* KBOARD EQU >8375 SKEY EQU >8374 SATAB EQU >0300 SDATA EQU >0400 * BALL DATA >3C7E,>FFFF,>FFFF,>7E3C SDATA DATA >7080,>8008 * STATUS EQU >837C SET DATA >2000 MYREG BSS >20
*
SPRITE LWPI MYREG LI R3,4 LI RO,SDTAB START LI R1,BALL LI R2,8 BLWP @VMBW AI R0,8 DEC R3 JNE START LI LI LI BLWP RO,SATAB R1,SDATA R2,6 @VMBW RO,SATAB+1 @VSBR R1,8 R1 MOVE R1,>00FF R1,8 @VSBW R8 R8 R8,800
* LOOP READ
* MOVE DELAY
JNE DELAY
APPENDIX D
215
* OUT
CLR @KBOARD BLWP @KSCAN MOV @STATUS,R3 @SET,R3 COC JNE LOOP INC R6 R6,4 CI JLT GO CLR R6 R6,1 CI JEQ MAG R6,2 CI DSIZE JEQ R6,3 CI DSIZEM JED Can you sum all this code into a two line statement?
* CHECK
* GO
* SMALL
RO,>01E0 LI WRITE JMP R0,>01E1 LI MAG WRITE JMP RO,>01E2 LI WRITE JMP R0001E3 DSIZEM LI WRITE JMP * WRITE BLWP @VWTR B @LOOP END
The next program places six red ball-shaped characters (not sprites) on the screen in a diagonal pattern. The screen is then scrolled upwards. This type of motion is familiar to anybody who has played the Alpiner game from TI. In oreder to run this program you must type GRAPH in response to the PROGRAM NAME? prompt. DEF GRAPH REF VSBW,VMBW,VMBR * DATA BALL COLOR DATA * COLTAB EQU PATTAB EQU * MYREG BSS * GRAPH LWPI LI >3C7E,>FFFF,>FFFF,>7E3C >8100 >0384 >0908 >20 MYREG RO,COLTAB
216
APPENDIX D
MOV @COLOR,R1 BLWP @VMBW RO,PATTAB LI LI R1,BALL LI R2,8 BLWP @VMBW LI R0,325 LI R1,>2100 LI R2,6 BLWP @VMBW AI R0,33 DEC R2 JGT LOOP BSS BSS 32 32
LOOP
LINE1 LINEX
*
SCROLL CLR RO LI R1,LINE1 LI R2,>20 BLWP @VMBR LI R00, 20 LI R1,LINEX LI R2,>20 BLWP @VMBR
*
LOOP1 LI R0,0 BLWP @VMBW AI RO,>40 CI RO,>300 JHE OUT BLWP @VMBR AI R0,>FFE0 JMP LOOP1 LI R0,>2E0 LI R1,LINE1 BLWP @VMBW JMP SCROLL END CB @KEYUP,@KEY JED PUP CB @KEYDN,@KEY JED PDOWN CB @KEYRT,@KEY PRIGHT JED CB @KEYLT,@KEY
*
OUT
*
OUT
APPENDIX D
217
PLEFT JEQ JMP START PUP LI JMP PDOWN LI JMP PRIGHT LI JMP PLEFT LI JMP R1,UP PRINT R1,DOWN PRINT R1,RIGHT PRINT R1,LEFT PRINT R0,325 R2,17 @VMBW START BEGIN
*
PRINT LI LI BLWP JMP END
APPENDIX E
219
AlP1FlaMOIX e.
c:Nois
Device is write protected. Bad open attribute. 1. incorrect file type. 2. incorrect record length 3. incorrect I/O mode 4. no records in relative record file Illegal operation. 1. conflict with OPEN attributes 2. peripheral does not support operation Out of buffer space on device. Attempt to read past end of file. File is closed. Device error. Mechanical or medium failure. File error. 1. program/data mismatch 2. openning non-existing file in INPUT
4 5 6 7
220
APPENDIX F
A F" IR INI ID I X F
E X
la
la FC F C3F E
This table lists errors that may be generated when you attempt to run your program. Error code 00-07 08 09 OA OB OC OD OE OF 10 11 12 13 14 15 16 17 18 19 1A IB 1C ID 1E 1F 20 21 22-FF Meaning Input/Output error MEMORY FULL INCORRECT STATEMENT ILLEGAL TAG . CHECKSUM ERROR DUPLICATE DEFINITION UNRESOLVED REFERENCE INCORRECT STATEMENT PROGRAM NOT FOUND INCORRECT STATEMENT BAD NAME CAN'T CONTINUE BAD VALUE NUMBER TOO BIG STRING-NUMBER MISMATCH BAD ARGUEMENT BAD SUBSCRIPT NAME CONFLICT CAN'T DO THAT BAD LINE NUMBER FOR-NEXT ERROR Input/Output error FILE ERROR INPUT ERROR DATA ERROR LINE TOO LONG MEMORY FULL Unknown error code
\
STUDY EXERCISES 221 02,111,1 TAD ICHIAIF" -T 1-11i.MFc
1. a) 1111 b) 0001 1000 c) 0111 0101 1010 1001 d) 1101 0111 1111 0110 2. a) 4 b) 9453 3. a) b) c) d) >F >18 >75A9 >D7F6
ICIUBTICOMB
4. a) 7220 b) 7220
=3,
4. a) Label field, Comment field, Operand field b) (*) asterisk c) Op-code field (operation code) 5. Assembler directives give instructions to the assembler program as to what to do with program instructions while the program instructions make up the actual object code. 6. NO (G is not a HEX character) 7. Op-code field (operation code)
IC4-111PCFNT IFZ
41-
1. * R3 CONTAINS VALUE MOV R3,R4 SLA R3,2 SLA R4,3 A R3,R4 2. Workspace Register 11 (R11)
222
STUDY EXERCISES
=. 256 bytes (>100) ,. 4. Conditional jump instructions 5. Return (RT) 6. a) b) c) d) WR,WR-indirect WR-autoincrement,WR Symbolic,Symbolic WR,Indexed
I--II Al IF* -11. FC ffi
1. a) b) c) d) e) 2.
It is an endless loop because R3 is constantly re-loaded and never will be equal to zero. DATA MOV >0000 R3,@SAVE
3. SAVE
,63.
LI LI BLWP
REF
VWTR
.L.
7.
REF
VWTR
\
STUDY EXERCISES 223
3. 4. 5.
Change the value of VDP register 1 to >01. Review pages 117 to 125. The computer views the screen as a series of memory locations in VDP RAM numbered >000 through >767. Place the entry point of the program in a END directive. The program will begin running as soon as it is entered.
6.