Appendix A -- Instruction Summary
Appendix B -- Binary and Hexadecimal Numbers
Appendix C -- Coding Form
Driving a car takes muscles (but not much) to turn the steering wheel, push the pedals, and so on. Programming a computer takes brains (but not much) to select the right instructions, anticipate the computer's response, and so on. Very few people do not have the necessary muscles to drive a car. Very few people do not have the necessary brains to program a computer. You probably can do both (at least after you finish learning what is in this book and if you already know how to drive).
You do not learn how to drive a car by sitting in your easy chair and waving your pinky in the air. You cannot learn how to program a computer by sitting in your easy chair and "speed-reading" this book. Plan on taking a couple hours or even a couple evenings on each chapter (except the first two, which are not very difficult). When you finish this book, you will know more about programming your computer than most computer hobbyists.
Beginning with Chapter 3, each chapter has a number of little programs which illustrate some feature of your computer. Put the program into your computer and run it (Chapter 2 tells you how to do this, in case you do not already know). The best way to understand each concept is to see it in use. Try to understand what is happening and why. To help your thinking, I will ask questions about what you see. Try to answer the questions before you go on, but if you are confused (and in this business we all are confused at some time or another), read a couple more sentences and I will try to give you some clues, or answer the question myself, but in different words. You should not try to go on to the next topic before you understand the previous one -- you will only become more confused.
I have tried to arrange this book so that every concept is built on the previous concepts. There is no need for "forward references". Each time I introduce a new term or jargon word, I give a definition. The word is printed in boldface so you can find it easily.
There is one more thing you should keep in mind when doing the problems in this book. The computer is not as smart as you are, and it will do just exactly what you tell it to do, even if you did not mean to tell it to do that. If the computer does not do what you think it should have done, 99.99% of the time it is because you did not tell it to do what you wanted. All of the programs in this book have been tested, and they work correctly. If you think a program is not doing what it should, check to be sure you put it in correctly. It is all too easy to read the letter "B" as the numeral "8" in the book (and vice versa), or to confuse the letter "B" for a "6" on the computer's output. Check your program in the computer against the book. Then check the book against the program in memory. If they match, it may be that you do not understand what is happening, so re-read the previous section(s).
Finally, don't let me scare you away. The computer is a lot of fun,
once you get the hang of it. It is a thrill without equal to be able to
command a machine to do some complicated task and to have that machine
obey your every command. So relax, and read Chapter 1.
A computer is a device which automatically performs an arbitrary sequence of operations on Data. The teletypewriter in the Realtor's office automatically performs a sequence of operations on data, but it is not an arbitrary sequence; you cannot cause it to perform a different sequence of operations tomorrow. The pocket calculator performs an arbitrary sequence of operations on data, but it is not automatic; you have to push a button for each operation. Note, however, that the more expensive "programmable" calculators in the strictest sense are computers, because you can set up a sequence of steps for it to follow, and it will do so automatically. The sewing machine can automatically perform a sequence of operations, but it operates on cloth and thread, not on data. What then is Data?
Data are the answers to questions. The answer may be numerical (Question: What is the result of adding 7 to 3, then dividing by 8? Answer: 1.25. Question: What is the fourth counting number? Answer: 4.) or logical (Question: If all men are mortal and Socrates is a man, is Socrates mortal? Answer: True.) or the answer may be a sequence of letters of the alphabet (Question: How is my name spelled? Answer: "Tom".). The answer may be long (Question: How did Columbus come to America? Answer: In three ships, the Pinta, the Nina, and the Santa Maria, which were paid for by the Spanish royal government in 1492, etc...) or very short (Question: How many apples are in an empty paper bag? Answer: 0.). A single Datum may be the answer to several questions at once (Questions: Who was the 38th President of the United States? What is the name of the second largest automobile maker in the world? How do you cross a shallow stream when there is no bridge? Answer to all three: Ford) or it may be the answer to a question nobody thought of asking: (Question: ? Answer: "@+!*=".). It is data if there could be at least one question for which these are the answers.
When the computer is not actually operating on it, the data is kept in memory. This is just as you might keep all the answers you know in your mind's memory. We often say the data is stored in the memory. For convenience, the memory is organized into a number of words, all the same size. A word may contain one answer or it may contain several small answers; large answers often require many words in memory. The smallest answer we can possibly have in a computer is either a "yes" or a "no". This is the same size as 0 or 1, True or False, Hot or Cold, or any other answer to a question which has only two possible answers. The amount of memory needed to store one of these smallest answers is called a bit. Each word in the computer memory is some fixed number of bits, say 8 or 16 or 60; the size of the computer word is determined by the person who designed the computer.
Most computers have several different kinds of memory. One kind is called RAM and will have hundreds or (usually) thousands of words. Another kind is called file storage and may have a million or more words, but it is harder for the computer to use this memory; more about this later. A third type of memory which most computers have is very easy for the computer to use. It is called registers, and there are usually only a few words of these. Often we tell computers apart by the number and kinds of registers they have.
Among the computer's registers, one (or sometimes several) is particularly important, because it holds the answer the computer is working on at any particular instant. Such a register is usually called an accumulator. It is normally a single word in the computer, and almost everything the computer is able to do to its data, it does to the data in the accumulator. I will mention some other useful registers shortly.
With thousands of words of data in memory (and we usually mean RAM when we say "memory"), one very important question to be answered is, "Where is the word I want?" We answer this question by numbering the words in memory, starting with zero (this turns out to be easier for the computer than starting at one). The number of each word is called its address, something like the number on your house. Obviously, every answer stored in memory has another answer associated with it, namely, "What is its address?" Often there are special registers in the computer that are particularly suited to holding this kind of data, that is, the addresses of other data stored in memory. We sometimes call these address registers. The computer is able to operate on the data in the address registers also.
Another very important kind of data in the computer memory answers the question, "What operation will the computer perform next?" This is important because we control the sequence of operations the computer performs by the proper arrangement of this particular kind of data. Each datum which answers the question, "What operation should the computer perform?" is called an Instruction, because it "instructs" the computer in its task. The whole sequence of instructions is called a Program. Of course there is an address register that points to the next instruction the computer will obey. This register is called the Program Counter or PC. Notice that the only difference between the data which you consider to be the answers to your questions and the data which are the answers to the computer's questions about what to do next is this: Who is doing the asking? When the computer asks, "What next?" the answer that comes out of memory is, by definition, an instruction. When the computer asks for data to operate on according to your program, the answer that comes out of memory is not an instruction, but "real data". (People usually prefer to say that the program is not data so we can use the word "data" to mean the answers to our questions, not those of the computer.)
When a computer is operating normally, we say it is running. It continually goes through the following pair of steps: First, the Program Counter is used to address an instruction; that is, the computer looks at the word in memory whose address is in the PC. This is called the instruction fetch. If the instruction occupies more than one word, all the words of this instruction are fetched. The PC is incremented (added to) by the number of words in the instruction, so that it now points to (i.e. addresses) the next sequential instruction in the program. Second, the computer performs or executes the operation specified by the instruction just fetched. The computer repeats this fetch-execute cycle for the next instruction, and so on, many thousands and millions of times.
The continuous repetition of the fetch-execute cycles in the computer may seem a little monotonous, until you realize that the instructions being executed are quite varied, and their sequence can make for programs having widely differing results. There are, for example, instructions to copy a datum from someplace in memory into the accumulator and others to copy the datum in the accumulator into some memory word; we call these loads and stores. There are instructions to add data to or subtract data from the accumulator, or to perform certain logical operations on it (which we will describe in detail in Chapter 5). There are instructions to manipulate the data in the other registers. Perhaps most important, there are instructions which can change the contents of the Program Counter; we call these branches. Chapter 3 covers these in some detail, but for now it is important to realize that the computer is able to alter its own sequence of program execution. Finally, there are instructions which interact with the outside world.
Up to now we have not mentioned how data gets into or out of the computer. I suppose it would still be a computer if it had no way to pass data out to the rest of the world or to accept new data to operate on, but it would not be worth much (a few of the really fast super-computers work this way, but they cheat). We mortals need what we call Input/Output or I/O.
Input refers to the way data gets into the computer. Usually the computer will have special registers which can be loaded with data from some external source, and perhaps some instructions by which the computer is able to copy this data into its internal memory. Output is the reverse operation: Some type of instruction enables the computer to copy data from its internal memory into special output registers, which the outside world is able to examine. Often these special Input and Output registers are called I/O ports. Input might come from a human being (such as some buttons or switches or a typewriter-like keyboard), or it may come from special equipment which operates the file storage. Similarly, output may go to lights for humans to look at, or perhaps to control the picture on a TV set; it may also go to the file storage.
Most file storage, as I mentioned earlier, is more difficult for the computer to use than its internal memory (RAM and registers). This is because it tends to be relatively slow, and the computer must pick off (on input) or send (on output) the words one at a time, at the right speed. If the file consists of magnetic tape (such as used with audio cassette systems) the speed may also depend on the human who is operating the controls.
In summary, then, we have seen that a computer consists of some kind of control mechanism (we really did not talk much about it, only assumed that it existed), and a memory consisting of registers and RAM, and some I/O. Perhaps there may be some file memory attached to the I/O. The computer operates on some of the data in memory, according to instructions in another part of the memory called the program.
In the next chapter we will look at a particular computer, and see how
it fits with this generalized picture.
The 1802 has a word size of 8 bits. All data in this computer comes in 8-bit pieces, which we call bytes. One byte can contain a single letter of the alphabet (or other typewriter character) or a small number (between 0 and 255). Most of the instructions for the 1802 will also fit into one byte each.
The basic ELF II comes with 256 bytes (or words) of RAM. You can buy more memory to expand this to 65,536 bytes. Inside the 1802 there are 20 registers, more or less. The lack of precision here is due to the fact that some of these registers are not accessible to you as the programmer and you may as well assume they do not exist; while others are not exactly one byte in size and might be counted once or twice, depending on your inclination. Instead of counting them, let us see exactly what the registers are, and what they can do in the computer:
Some of the bits in the opcode tell the computer what kind of instruction it is, while others may select one of the registers or further specify the operation. In the case of the 01010011 byte, the first four bits tell the 1802 that this is a store instruction, and the last four bits point to an address register. Thus all of the opcodes from 80 through 95 are store instructions, using different address registers.
Some of the instructions come with data attached. The 1802 can tell which these are by the particular bits in the opcode, so it knows to go back to memory for another byte. Other opcodes contain bits that tell the computer that there is an address (or a piece of an address) attached to the instruction, so the 1802 goes back to RAM for one or two more bytes as part of this instruction. When I describe each instruction, I will tell you exactly how many bytes the 1802 will expect to come with its opcode.
In a similar way, some of the instructions depend on X to indicate which address register to use, while others (like the store instruction mentioned) have that information as part of the opcode. Still others do not directly use any address register. Here also I will give the details when I describe the instructions.
In Chapters 3-6 we will be looking at exactly how the 1802 in the ELF II executes each instruction in its repertoire (the list of instructions the computer knows how to execute). But first let us get a general notion of how the computer works.
Look at your ELF II. You will notice three toggle switches (or possibly locking pushbuttons) on the right hand side near the edge of the board; the bottom switch (closest to you) is labeled "M/P" for "Memory Protect". When this switch is on (positioned away from you in the direction of the little arrow, or locked down), the RAM memory is protected from being accidentally changed by you or the computer; in other words, while the switch is on, nothing new can be stored into memory, even by those instructions or operations which normally would store into it.
The next switch is labeled "LOAD", and is used to load data (and programs) into the computer before running. This switch works with the third switch, labeled "RUN". When both the LOAD and RUN switches are off (towards you), the computer is reset, that is, put into a known initial state or condition. This is so that the computer will always start executing the first instruction of the program. Specifically, when the 1802 is reset, X and P are both set to point to R0, which is also set to zero so that it will point to the first byte in memory. IE is also set to the enabled state, but that does not concern us now.
When the switches are in the combination RUN off, LOAD on, M/P off, the computer is able to manually load bytes from the hex keypad. You push the keys corresponding to the hex code of the byte you want entered, then push the "I" (for "Input") key once. The byte that was entered into memory shows up on the two-digit hex display just above the keypad. For the next byte you repeat the sequence. We will call this combination of the switches the Load mode. The 1802, when operated in this way, uses address register R0 to point to the memory byte to be loaded next. Since this register is inside the 1802 you cannot see it, so you have to count the number of times you push the "I" key to know which memory byte will be loaded next. Later I will show you a few tricks to make it a little easier to know where you are. If you entered the Load mode from the Reset state (both RUN and LOAD off), you know that R0 points to memory address 0, which is the first location in memory. Therefore the first byte you enter will go into memory location 0, the second byte will go into location 1, the third into location 2, etc. If you ever lose count, you probably have to reset the computer (turn the LOAD switch off, then back on) and start over. I have done this many times myself, so you should not feel badly if this happens to you rather often.
You recall I said that the M/P switch protects memory from both the computer and you. Let's talk about you. If you enter the Load mode and then turn the M/P switch on, you will find that the computer thinks it is loading bytes into memory, but since memory is not changing, what you see on the hex display is not what you loaded, but what was there before. This is a convenient way to examine the contents of memory, so we'll call it the Examine mode. You can turn the M/P switch on and off as often as you like, thus switching between the load mode and the examine mode. Doing this does not affect R0 (you have to reset the computer for that), so you can examine a few bytes, store something new into the next byte, then go back to looking at what is already there after that. Thus if you make a mistake on the 13th byte of your program, you can correct the mistake without re-keying the whole program by resetting, examining the first 12 bytes (you already know they are right, but you can look at them anyway), then loading the 13th byte, and continuing. You will probably find that you make more than one mistake in a single program, so it is best to save all your fixups for a single pass. This way you only need to step through memory three or four times; once to load the original program, once to examine it and see where all the errors are, once to correct those errors, then finally one more time to make sure you got them all right. Obviously it is very important that you write down on a piece of paper exactly what hex codes you are going to put into each memory byte. More on this later.
After loading your program into the ELF II you probably want the computer to execute it. This is done by setting RUN on, and LOAD off. We will call this the Run mode. It is generally best to enter the Run mode from the Reset state. That is, turn both switches off, then turn the RUN switch on. Since P is 0 and address register R0 is also 0, the first instruction to be executed will be the byte you loaded into location 0. The second instruction will be the byte you loaded into location 1 (unless the first instruction was more than one byte; in that case the second instruction may come from memory location 2 or 3). Chapters 3-6 are a detailed description of how each instruction is executed, so I will say no more at this time.
The fourth possible combination of the RUN and LOAD switches is both on. This is called the Wait state because it is used to stop the computer from executing without resetting it. If you put the computer back in the Run mode, it will continue where it left off. Wait will also stop the computer from proceeding in the Load mode, but that is not of much value, since it is normally waiting for you to push the "I" key anyway. You cannot depend on switching the computer from Load to Run, or from Run to Load by going through Wait, because whatever the computer is doing when it enters the Wait state is not finished, and so it may not be able to properly start up in the other mode.
All of the programs given as examples in this book follow a fixed format. After you have used this format for a while you will begin to find that reading programs written in this format is much easier than when they are some other format. I strongly urge you to use the same format, at least until you get used to programming and find something better. Appendix C in the back of this book is a blank page ruled for coding this format; you may wish to use it to make several photocopies, or you may prefer to buy one or more pads of ruled forms from Netronics.
The Coding Form is divided into six columns, identified as: Location, Code, Label, Mnemonic, Operand, and Comments.
Now reset it, turn the M/P switch off, then run the program. Examine
memory again. What happened to the program? What about the rest of memory?
We call this program a Memory Clear, because it clears (almost)
all of memory to zeros. Notice that most of the program is still there!
Occasionally I will suggest that you clear memory before trying some experiment;
by that I mean, put Program 2.1 in and run it.
By the way, don't worry about trying to understand these programs right now. I will explain how they work in Chapter 5.
.. PROGRAM 2.1 -- MEMORY CLEAR .. 0000 90 CLEAR: GHI 0 .. REGISTER 0 HAS 0001 0001 AE PLO 14 .. MAKE RE=0000 0002 BE PHI 14 0003 EE LOOP: SEX 14 .. EACH TIME, R14 IS -1 0004 73 STXD .. D STILL HAS 00 0005 30 BR LOOP .. GO BACK FOR ANOTHER 0006 03 .. PROGRAM 2.2 -- MEMORY SEQUENCER .. 0000 90 SEQ: GHI 0 .. THIS PART IS 0001 AE PLO 14 .. JUST LIKE CLEAR 0002 BE PHI 14 0003 EE LOOP: SEX 14 0004 8E GLO 14 .. THIS IS ADDRESS VALUE 0005 73 STXD .. SO DATA=ADDRESS 0006 30 BR LOOP .. REPEAT UNTIL DONE 0007 03 .. PROGRAM 2.3 -- SLOW BLINK .. 0000 91 BLINK: GHI 1 .. LOOK AT TIMER IN R1 0001 CE LSZ .. IS ZERO ONLY 1/256 0002 7A REQ .. IF NOT 00, Q OFF 0003 38 SKP 0004 7B SEQ .. WHILE ZERO, Q ON 0005 11 INC 1 .. BUMP COUNTER 0006 30 BR BLINK.. THEN REPEAT 0007 00
Each instruction is presented in a standard format. First I will give you a test program which you can key into your ELF II to demonstrate the operation of the particular instruction. Associated with this program will be a discussion of just what you should look for when running this program, and perhaps some hints about further experiments. Following this will be a formal definition of the instruction for future reference. This will have a title line in bold face with the instruction mnemonic, hex opcode, the type of operand (if any), and a short descriptive name. The following are the operand types which the 1802 uses, but do not be overly concerned about understanding them now; I will explain each one when you first use it:
.. PROGRAM 3.1 -- TEST IDL .. 0000 00 IDL .. **Key this program into your ELF II, then switch it to Run mode. Did you see anything happen? Try pushing some of the keys. Any results? If you put this instruction in carefully, the computer should just sit there doing nothing, idle. In fact, the instruction is called the IDLE instruction, because it stops the computer. Since this program does nothing else, there is nothing to see. How can you tell the computer is actually stopped? You can't; you have to take my word for it. It is important that you realize that the ELF II does not tell you it has stopped. If you had an oscilloscope you could look at the SC0 line on the CPU chip; it toggles up and down while the computer is running; you might even want to wire up an LED to tell you that it is toggling, so that you will know when your computer has stopped. That is outside the scope of this book, so for now, you have to believe that the IDL instruction really does what it is supposed to. Later on we will try some experiments to see how it differs from the other instructions.
IDL Idle 00 ------------------------------------------------------------- Stop the execution of instructions, and wait for an interrupt or DMA to resume.Now that you understand all about the IDL instruction, we will use it at the end of the next test program:
.. PROGRAM 3.2 -- TEST SEQ .. 0000 7B SEQ .. ** 0001 00 IDL .. STOPKey this program in, and run it. What happened? Obviously, since there is only one more instruction than in the previous program, that instruction is what causes the Q light to go on. The Q is a kind of funny bit of memory inside the 1802 which is connected to the outside world. Therefore we can say that SEQ is an Output instruction: It outputs a "1" or "yes" or "on" to that part of the circuit that lights the little LED.
SEQ Set Q 7B ------------------------------------------------------------- Set the Q flip-flop in the 1802 on, and set the Q output pin high.You will notice that this next program looks very similar:
.. PROGRAM 3.3 -- TEST REQ .. 0000 7A REQ .. ** 0001 00 IDL .. STOPWhen you run this program, what happens to Q? You say you cannot tell the difference between this program and the first one? That is because Q is being set to "0" or "off" by the REQ instruction, but it is already off because Reset turns it off. Moral of the story: If an instruction commands the computer to do something that has already been done, it does it again, but you have no way of being sure of the fact. Try this program instead:
.. PROGRAM 3.4 -- TEST REQ AFTER SEQ .. 0000 7B SEQ .. TURN IT ON FIRST 0001 7A REQ .. TURN IT OFF AGAIN 0002 00 IDL .. THEN STOPWhen you run this program, turn the lights out in the room and put your thumb over the hex digit display, then flip the Run switch on while watching the Q light carefully. You might see a very faint blink of light. Computers are fast! If you do not see anything, try 50 or 100 SEQ's followed by one REQ and the IDL; a 1 millisecond flash of light is easier to see than 11 microseconds. The point is, the SEQ turned the Q light on, then the REQ turned it off. Thus the REQ is also a sort of output instruction.
REQ Reset Q 7A ------------------------------------------------------------- Turn the Q flip-flop in the 1802 off, and set the Q output pin low.Now the computer is able to tell us about what it is doing. Let's complete the loop by looking at an input instruction.
.. PROGRAM 3.5 -- TEST B4 .. 0000 7B SEQ .. TELL THE WORLD 0001 37 B4 4 .. ** 0002 04 0003 7A REQ .. TURN Q OFF!! 0004 00 IDL .. STOPWhen you key in this program and run it, what happens to Q? Does it look any different from program 3.4? Now reset the computer, and while holding the "I" key depressed, flip it into Run mode again. What happened to Q this time? Why did it not go off? To convince yourself that the "I" key has no effect on the REQ instruction, put program 3.4 back in, and run it with the "I" key depressed. Obviously, the new instruction we added in program 3.5 is somehow looking at the "I" key, and making the REQ instruction not work. For the next experiment, clear memory (i.e. run program 2.1, or key in 256 00's by hand). Then key in this program:
.. PROGRAM 3.6 -- TEST B4 DESTINATION .. 0000 7B SEQ .. TURN IT ON 0001 37 B4 18 .. ** 0002 12 0003 7A REQ .. TURN Q OFF 0004 00 IDL .. STOP HERE 0005 00 IDL .. (SPACE FILLER) 0006 00 IDL 0007 00 IDL 0008 00 IDL 0009 00 IDL 000A 00 IDL 000B 00 IDL 000C 00 IDL 000D 00 IDL 000E 00 IDL 000F 00 IDL 0010 00 IDL 0011 00 IDL 0012 7A REQ .. Q OFF HERE TOO 0013 00 IDL .. STOP ALSO 0014 00 IDL .. ETC...Be sure you count the IDL's very carefully when you key this program in. Now when you run it, Q should blink on and then off (you may not see it blink in bright light) whether you start with the "I" key depressed or not. Now go in and modify the third byte of this program (the hex 12 in memory location 0002) to hex 13, and try again. Notice that now the Q light stays on if you run the program with "I" depressed. Now change memory location 0013 (this is the 20th byte, which is the next one after the REQ in location 0012) from IDL (00) to REQ (hex 7A), and try the program again. Finally, change the REQ in memory location 0003 to an IDL (00) and run the program to see how pressing the "I" key affects it. By now you should have noticed that when the "I" key is not pressed, the next instruction after the B4 is executed in sequence, but if the "I" key is pressed the next instruction to be executed is the one whose address is in the byte immediately following the B4 opcode. If you are not yet convinced of this, try putting an SEQ at any place in the first 256 bytes of memory you like, with zeros (IDL instructions) elsewhere, and a B4 instruction (hex 37) in the first byte. When the second byte has the hexadecimal equivalent of the location where you put the SEQ, then running the program with "I" depressed turns Q on; otherwise Q stays off.
We call the B4 a branch instruction because the flow of program execution takes one branch of a fork when B4 is executed. That is, depending somehow on the "I" key, the computer either takes the next instruction in sequence, or it starts executing instructions from some other part of memory. The exact place in memory where it goes for that next instruction is defined in the byte immediately following the opcode, and the two bytes together are one instruction.
We also say that the B4 instruction is an Input instruction, because it causes the internal memory of the computer to change depending on conditions external to the computer itself. In this case the memory that is changed is the Program Counter register. The external condition that the 1802 sees is called EF4 (for External Flag 4). If you look on the schematic for the ELF II computer, you will see that the "I" key is connected (somewhat indirectly) to the EF4 pin on the CPU. As you might guess, there are also EF1, EF2 and EF3 pins, but on the basic ELF II some of these are not connected to anything, and others are hard to observe. I hope you can assume that B1, B2, and B3 work the same way as B4, but look instead at their own EF lines.
B1 a Branch on External Flag 1 34 aa B2 a Branch on External Flag 2 35 aa B3 a Branch on External Flag 3 36 aa B4 a Branch on External Flag 4 37 aa ------------------------------------------------------------- If the corresponding external flag line is True (i.e. the pin is electrically low), then take as the next instruction the one found at the address which is in the second byte of the instruction. If the flag is False, advance to the next instruction in sequence and ignore the address in the second byte of this instruction.We say "the branch is taken" when the address is used to determine the location in memory of the next instruction. You will recall that the PC is actually a 16-bit register, but there are only 8 bits in the address part of the B4 instruction. We cheat a little bit here; the low 8 bits of the PC get replaced by the branch address, and the high 8 bits are left unchanged. Later in this chapter we will look at branch instructions that replace the entire PC with a new address.
All of the conditional branches in the 1802 have a matched set of branches which test for the reverse condition. In other words, instead of testing for EF4 true as B4 does, we can also test for EF4 false. If you want to see how this works, put program 3.5 or 3.6 back into the computer, but change the 37 to 3F and see how it runs differently. As you become familiar with the 1802 instruction set, you will discover that the branch instructions are paired in such a way that the true version differs from the false version in only one bit position of the opcode; that bit is 0 for the branch if true, 1 for the branch if false.
BN1 a Branch on Not External Flag 1 3C aa BN2 a Branch on Not External Flag 2 3D aa BN3 a Branch on Not External Flag 3 3E aa BN4 a Branch on Not External Flag 4 3F aa ------------------------------------------------------------- If the corresponding external flag line is False (i.e. the pin is high electrically), then take as the next instruction the one found at the address which is in the second byte of the instruction. If the flag is True, advance to the next instruction in sequence and ignore the address in the second byte of this instruction.Well you might say, if the 1802 can branch when a condition is true, and it can branch when the condition is false, is there some way we can convince it to branch always? The answer is obviously yes, as the next program shows:
.. PROGRAM 3.7 -- TEST BR .. 0000 7A REQ .. Q OFF 0001 3F BN4 4 .. TEST EF4 0002 04 0003 7B SEQ .. Q ON IF EF4 0004 30 BR 0 .. ** 0005 00When you first run this program, it will not look particularly different from the other programs that do nothing. But now, push the "I" key without resetting the computer, then release it. What happened to the Q light? The computer did not stop! When the program counter reached location 0004, it simply branched back to location 0000 and repeated what it had just done. We call this a loop. Notice that every time through the loop Q is turned off, but only if EF4 is true (i.e. the BN4 does not branch) is it turned on. If Q is turned off every time through the loop, why is it on (unblinking) when the program is running? To help answer that question, try flipping the computer into the wait state a few times while you hold the "I" key down. Notice how sometimes the Q goes off and sometimes it gets just a little brighter. What you are doing is stopping the computer at various points in the loop. Can you predict which times Q will be on when you stop it? (I can't).
BR a Branch unconditionally 30 aa ------------------------------------------------------------- Take as the next instruction, the one whose address is the second byte of the BR instruction.As I said earlier, the two-byte branch instructions only have one byte of address with which to modify the PC. The 1802 also has three-byte branch instructions which replace the entire PC with the contents of the two bytes following the opcode; the first byte is the most significant eight bits, and the second is the least significant eight bits. Try to convince yourself this is true by clearing memory, then storing a single SEQ somewhere. Put a hex C0 in location 0000 and the address of the SEQ (in hex) in bytes 0001 and 0002. When you run the program, Q should come on if and only if the address of the SEQ exactly matches the address in those two bytes. Notice that it does not depend on the "I" key.
LBR aa Long Branch unconditionally C0 aaaa ------------------------------------------------------------- Take as the next instruction, the one whose address is the second and third bytes of the LBR instruction.Exercise: What happens when a branch instruction branches to itself? See if you can think of a test program to show this happening. Hint: try a BN4. We have seen an example of an output instruction and an input instruction in the 1802. Yet neither is called "input" or "output". This is because there are other instructions which also do input or output. Key in the following program:
.. PROGRAM 3.8 -- TEST OUT .. 0000 64 OUT 4 .. ** 0001 00 .. (DATA TO BE OUTPUT) 0002 3F BN4 0 .. LOOP BACK 0003 00 0004 64 OUT 4 .. ** 0005 11 .. (DATA TO BE OUTPUT) 0006 30 BR 2 .. LOOP BACK 0007 02When you run this program, watch the hex display. Then push the "I" key and see what happens to it. By changing the contents of locations 0001 and 0005, convince yourself that the OUT 4 instruction puts the contents of the next byte out on the hex display. Later on we will see that this is true only if P=X, which in this case is true (both are set to zero by reset). Try as an experiment, OUT 2 (hex 62) in location 0000; what happened to the display? If you try OUT 1 you may find that the whole program goes crazy; I will explain why in Chapter 7.
Now clear memory (run program 2.1) and key in program 3.9:
.. PROGRAM 3.9 -- TEST INP .. 0000 3F BN4 * .. WAIT FOR "I" 0001 00 0002 6C INP 4 .. ** 0003 7B SEQ .. WATCH THIS!! 0004 00 IDL .. STOP 0005 00Before you run this program (if you already ran it, go back and verify that the program is still there) turn on the M/P switch. This is important, because this program modifies itself! I will have more to say about programs that modify themselves later. Run the program once with the M/P switch on, so you can see how it works. Notice that Q does not come on until you push the "I" key. (Why?) Now push the "0" key twice and run the program again (with M/P still on). Is it any different? Reset the computer and convince yourself that the program is still all there (i.e. go into the Examine mode and look at it). Now you are ready to run the program with the M/P s witch off. While the computer is still reset, push the "0" key twice, and turn off the M/P switch. Now run the program: When you push the "I" key, what happens to Q? To find out why, (be sure to turn the M/P switch back on and) examine your program. What happened to the SEQ instruction in location 0003? Run the program again, and before pushing the "I" key, be sure the M/P is off again, and push the "7" key, then the "B" key. Now what happened? Try running the program a few more times, but each time push a different sequence of keys: try 7,A; 6,4; 3,0. Reset the computer each time and examine 0003 to convince yourself that whatever pair of keys you push shows up in the byte following the INP 4 instruction. Try another experiment: change the INP 4 to INP 2 (hex 6A); does the keypad have any effect on what goes into location 0003 now?
As you should have noticed by now, both the INP and OUT instructions have the left hex digit 6. The right digit is between 1 and 7 for OUT and between 9 and F for INP. As it turns out, the same bit which determines whether a conditional branch tests the true or false of a condition also determines whether an I/O instruction with left digit 6 is OUT or INP. You can think of it this way: If the bit is "0" it is "OUT"; if the bit is "1" it is "INP" (relating 0=O, 1=I). We do not yet have any way to prove it on your computer, but input and output use the X register to select an address register to point to the memory byte being input or output. In Chapter 4 we will try to nail that aspect down. Meanwhile you should notice that the OUT instruction increments R0 when the byte is output (go back and look at Program 3.8: Did the computer ever use the byte to be output as an instruction? Convince yourself by looking at OUT 4 followed by 00= IDL or 7B=SEQ). Notice that in our examples R0 was both Program Counter and data pointer. In the case of the INP instruction, however, whatever was input into memory following the INP 4 instruction was also executed as another instruction; in other words, when the INP used R0, R0 was not incremented, so the next instruction fetch (which is also using R0 as PC) will fetch out the same byte which was just input. Be sure you understand this difference.
OUT p Output from memory (p = 1 to 7) 6p ------------------------------------------------------------- Output on the port p, the memory byte pointed to by the address register pointed to by X, then increment the address register. INP p Input to memory and D (p = 9 to F) 6p ------------------------------------------------------------- Input from the port p, a byte to be stored into the memory location pointed to by the address register pointed to by X, and also place the byte into D.For both the OUT and INP instructions, the low three bits of p come out on the "N" lines of the 1802 chip; these may or may not be decoded into seven separate ports; if not, then only three ports are distinguishable (1, 2, and 4).
Program 3.10 is rather complicated, and I would recommend that you sequence memory before keying it in. This will help you to place the two pieces which are located at some distance from the beginning. You will also notice that I have arranged it so that each OUT instruction outputs a byte with its own address. This can serve as a check on your keying: After keying in the 64, turn on the M/P switch and examine the next byte; it should already be correct. When you get to location 000F, switch into Examine mode and step through memory to location 002F, then go back to the Load mode for location 0030. Do the same for 0034 to 0079. The first byte after the end of your program should be at 007E.
.. PROGRAM 3.10 -- CONDITIONAL BRANCHES .. 0000 37 B4 * .. WAIT FOR "I" RELEASE 0001 00 0002 64 OUT 4 .. ANNOUNCE OURSELVES 0003 03 ,03 0004 7B SEQ .. ALSO TURN ON Q 0005 3F BN4 * .. WAIT FOR "I" 0006 05 0007 6C INP 4 .. GET INSTRUCTION 0008 7A (REQ) .. DO IT ** 0009 30 BR 122 .. GOTO 7A 000A 7A (REQ) .. Q OFF IF EXECUTED 000B 64 OUT 4 .. ANNOUNCE "HERE" 000C 0C ,0C 000D 30 BR 0 .. DO IT AGAIN 000E 00 .. 0030 64 OUT 4 .. ANNOUNCE "HERE" 0031 31 ,31 0032 30 BR 0 .. GO BACK 0033 00 .. 007A 64 OUT 4 .. ANNOUNCE "HERE" 007B 7B ,7B 007C 30 BR 0 .. GO BACK TO FRONT 007D 00Examine this program carefully before running it. Notice that there are four OUT instructions, but each one should output a different value. Therefore you should always know where the program was executing by what you see on the hex display. The program contains no instructions which you do not understand, so you should be fully convinced about what it will do when you run it, before you run it. In particular, you should be convinced that as coded, there is no way for the program to output either "0C" or "31"; it should alternate between "7B" and "03" as you push and release the "I" key. Turn on the M/P switch and verify that this is so by running the program. Notice that as long as the M/P switch is on, none of the other keys have any effect. Notice also that the REQ instruction in location 0008 turns off the Q when you push the "I" key.
Now turn off the M/P switch. The program should be waiting for you to push the "I" key, which you know because the hex display shows "03". First push the keys "7", "B", and then "I". Push and release "I" a few times so you know what is happening. What happened to Q? Is anything else different? Now push "7", then "A". Convince yourself that you are able to key in the opcode that the computer will execute when you push the "I" key. Remember, the INP instruction is inputting a byte into the memory location pointed to by the PC, so that byte input from the keypad becomes the next opcode. Experiment with a few opcodes that you understand, like 00=IDL. What happened? Notice that the computer is no longer running, so it cannot respond to the "I" key. Reset and try again with 30=BR. What happened this time? Why? Look again at the program, and try to convince yourself that the computer did exactly what it should have done. First it executed an INP instruction which input the 30 into memory location 0008 (if you don't believe it, reset the computer and examine location 0008). Then it executed the byte in 0008, which is the opcode of a BR instruction. But this is a two-byte instruction, so location 0009 is fetched to be used as an address. 0009 also contains 30 (it is the opcode of another BR instruction, but the computer does know that at this time). So the computer branches to location 0030, which is an OUT 4 instruction.
Now let's try some new opcodes. Remember I said that each branch instruction had a paired opcode which branches on the false of the same condition? It is bit 3 of the opcode that makes the difference (that is an 8 in the second digit: 0-7 has a zero in bit 3; 8-F has a one in bit 3). You already know about the difference between 37=B4 and 3F=BN4. Does it work for 30 (which is branch always)? Is there a "branch never"? Try it. If the opcode in 0008 is "branch never" then what is the next instruction to be executed? No, it is not in 0009, because all branch instructions are two bytes, even if the branch is not taken (to convince yourself of that, review what you learned about the B4 instruction). We thought that location 000A was the second byte of a BR instruction, but it seems that the computer thinks it is the next opcode. So off goes Q, and pretty soon the OUT 4 at 000B gets executed.
There is a moral to this lesson, besides what you learn about the new instructions. That is, the computer is the final judge of what your program is going to do. It does not matter much if you think that such and such a location in memory is part of a two-byte instruction; when the computer fetches the second byte during an opcode fetch then it is an opcode. As in religion, if you want to avoid being surprised at the end, you have to follow the rules laid down by the final judge.
But what good is a "branch never"? Not much, as such. However, do notice that the second byte has no effect on its execution (it never uses the branch address), so we can put anything we want there. In fact, if it is a one-byte instruction, then the 38 instruction effectively skips over it, so we call this instruction SKP for "skip". It does not do anything the BR instruction could not do, but it does it in one byte instead of two.
SKP Skip one byte 38 ------------------------------------------------------------- The one-byte instruction following the SKP opcode is skipped.Program 3.10 is not set up to demonstrate the operation of long branches, but you can try the "long branch never". What would you expect to happen? In other words, what will be the next instruction after a C8 opcode? Try it. How is this different from 38=SKP? If Q does not go off, then obviously the REQ "instruction" in 000A is not being executed. Since you see "0C" on the hex display, you have to assume that the BR in 0009 is not being executed either, but that the OUT 4 in 000B is being executed. We call the C8 opcode a "Long Skip" because it skips two bytes.
LSKP Long Skip C8 ------------------------------------------------------------- Skip the two bytes following the opcode.Let me quickly introduce you to the instruction that does nothing. Try the opcode "C4" in Program 3.10. What happens? Obviously it is not a skip or branch, because the branch in 0009-000A is executed. It does not turn Q off; it does not output anything that you can see. You will have to take my word for it that it does nothing else. We use it when we want the computer to kill some time, or we want to leave some space in a program for later additions, or we want to remove an instruction without moving the whole program back down.
NOP No Operation C4 ------------------------------------------------------------- This instruction does nothing, except take three major cycles to execute.Let's try a new conditional branch. Enter the value "32" into Program 3.10. What happens? How is this different from the 38=SKP? If you agree that it does not seem to be different, turn on the M/P switch (so that the 32 in location 0008 will not be changed by subsequent entries), then try entering various other pairs of digits. What happens if you enter "00"? Can you find any other pair of digits that is distinctive? Convince yourself that this only works with the 32 opcode, and not with the 38 or 30 opcodes. Why did I tell you to turn on the M/P switch for this test? If you enter 00 with the M/P switch off, what happens to the program? Evidently, after an INP instruction in which the byte that was input is 00 the 32 opcode branches, but for all other bytes, the 32 opcode does not branch. If you go back and review the formal definition of the INP instruction, you will notice that it not only inputs to memory, but the same byte is also placed in the accumulator, D. When memory is protected, memory cannot be altered so only D is changed. The 32 opcode branches if D is exactly equal to zero, and not otherwise.
BZ a Branch on Zero 32 aa ------------------------------------------------------------- Branch if D is zero; otherwise execute the next instruction in sequence (after the branch address).If there is a Branch on Zero, is there also a Branch on Not Zero? What would be its opcode? Try it.
BNZ a Branch on Not Zero 3A aa ------------------------------------------------------------- Branch if D is not exactly 00; otherwise take the next instruction in sequence (after the branch address).If you think about it for a minute you will realize that there might also be a Long Branch on Zero and a Long Branch on Not Zero. As I said, Program 3.10 is not set up to test long branches, so you cannot use it to observe these instructions in action.
Exercise: Write a program to test LBZ and LBNZ. Convince yourself that these are three-byte instructions that can branch anywhere in memory.
LBZ aa Long Branch if Zero C2 aaaa ------------------------------------------------------------- If the accumulator D is exactly zero, replace the contents of the Program Counter with the second and third bytes of this instruction; otherwise proceed to the next instruction in sequence. LBNZ aa Long Branch if Not Zero CA aaaa ------------------------------------------------------------- If the accumulator D is not exactly zero, replace the contents of the Program Counter with the second and third bytes of this instruction; otherwise proceed to the next instruction in sequence.There are two more instructions which you can learn about using Program 3.10. This time run it once with M/P off and enter "C", "6". Notice that it behaves like an LSKP instruction. Now turn on M/P so you can feed the new opcode various data bytes. Did you try 00? What happened? Notice that opcode C6 skips when D is not zero; when D is exactly zero the instruction in 0009 is executed. Now try the opcode "CE". We call these "Conditional Skips". Notice that the condition being tested seems to be the reverse from the conditional branches. If you think about it, you will also see that C4=NOP is really a "Skip Never". Do you think the CC opcode would be a "Skip Always" instruction? What about C8=LSKP? Try CC. We will come back to this one.
LSZ Long Skip if Zero CE ------------------------------------------------------------- Skip two bytes if D is zero; otherwise execute the next byte in sequence after the LSZ opcode. LSNZ Long Skip if Not Zero C6 ------------------------------------------------------------- Skip two bytes if D is not zero; otherwise execute the next byte in sequence.Let us look at one more condition before moving on to the register operations. Key in Program 3.11:
.. PROGRAM 3.11 -- TEST Q CONDITIONALS .. 0000 7A REQ .. Q OFF 0001 6C INP 4 .. GET NEXT OPCODE 0002 7B (SEQ) .. MAYBE Q ON AGAIN 0003 C1 LBQ 10 .. ** 0004 00 0005 0A 0006 64 OUT 4 .. NOTE NO BRANCH 0007 11 ,11 0008 30 BR 0 .. REPEAT 0009 00 000A 64 OUT 4 .. NOTE BRANCHED 000B 33 ,33 000C 30 BR 0 .. REPEAT 000D 00First run this program with M/P on. What shows on the hex display? Notice that the program does not wait for or depend on EF4, so it is ignoring the "I" key. Now push the keys "7", "A", and flip the M/P switch off. What happened to the hex display? What is the difference between the program as it is now running and how it was running a few minutes ago? Flip the M/P switch back on and try entering other data: Is there any change? Clearly, the program is different depending on whether it is executing 7A=REQ or 7B=SEQ in location 0002. Obviously the new instruction in 0003-0005 depends on Q. As you probably guessed by now, it is a Long Branch if Q is on. Change location 0003 to hex C9. What do you think this will do to the program? Try it.
LBQ aa Long Branch if Q is on C1 aaaa ------------------------------------------------------------- Branch to the location whose two byte address follows this opcode if Q is on; otherwise ignore the address and take the next instruction in sequence. LBNQ aa Long Branch if Q is off C9 aaaa ------------------------------------------------------------- Branch to the location whose two byte address follows this opcode if Q is off; otherwise ignore the address and take the next instruction in sequence otherwise.As you might have guessed, there is also a Short Branch on Q. To test this, put a NOP=C4 into location 0003, then a hex 31 into location 0004. Leave the "0A" in location 0005; it is the second byte of the branch. Try it. Then change the 31 to hex 39. Notice that after entering 7B to the running program, the "31" opcode branches; after entering any other pair the "39" opcode branches.
BQ a Branch If Q is on 31 aa ------------------------------------------------------------- Branch to the location whose one-byte address follows this opcode if Q is on; otherwise ignore the address and take the next instruction in sequence. BNQ a Branch if Q is off 39 aa ------------------------------------------------------------- Branch to the location whose one-byte address follows this opcode if Q is off; otherwise ignore the address and take the next instruction in sequence.And of course, there is a "Skip if Q". To test this, replace 0003-0005 with the three bytes CD, 64, FF. Now when you run the program, if Q is on what do you see? When Q is off, what happens? Where is the OUT 4 instruction followed by "AA"? To help you answer this question, try switching the computer into Wait a few times. If your eye sees "FF" and "11" in rapid succession, what will it look like? Now change the CD in location 0003 to C5 and run the program again, alternately pushing 7B and 7A on the keys. Do you think you understand this skip instruction? If not, reset the computer and write down the contents of memory from 0000 to 0009. See if you can think like the computer as it would to execute the bytes in the program. Does that help?
LSQ Long Skip if Q is on CD ------------------------------------------------------------- If Q is on, skip two bytes; otherwise execute the next byte after this opcode. LSNQ Long Skip if Q is off C5 ------------------------------------------------------------- If Q is off, skip two bytes; otherwise execute the next byte after this opcode.Now we have learned all of the 1802 instructions which do input or output; these are INP, OUT, B4, BN4 (also B1, B2, B3, etc.), SEQ and REQ. We have learned most of the conditional skips and branches: BZ, BNZ, LBZ, LBNZ, LSZ, LSNZ, BQ, LBQ, LSQ (and BNQ, etc.), and B4 etc. and all of the unconditional skips and branches: BR, LBR, SKP, and LSKP. And we know how to use NOP and IDL. If you look at the opcodes for these instructions, you will see that they include all the opcodes that begin with 6 except 60 and 68. Opcode 68 is not a defined instruction for the 1802 (though it is for the 1804, 1805, and 1806). We will discuss 60 in the next chapter. You will see that we have covered all the opcodes that begin with 3 except for 33 and 3B, and all those that begin with C except C3, C7, CB, CC, and CF. Opcode CC has to do with the interrupt system, which we will cover in Chapter 6. All the others are conditional skips and branches which test the DF or carry flag. Since I have not yet shown you how to set or clear the carry flag, you have no way to see how these conditionals work. For now, please accept that they look similar enough to the other conditional skips and branches that you do understand, so that when we get to DF, you will have no particular trouble with these instructions.
There is one form of input and output which your computer is capable
of that does not use input or output instructions. We call it DMA
or Direct Memory Access because it goes directly to memory without
affecting the program (except for the time it takes to cycle memory). We
will discuss this in some detail in Chapter 7.
Put Program 3.10 back into your ELF II. With M/P off, run the program and key in "10". What happens? How is this instruction different from a SKP? What happened is that this instruction incremented R0 (by increment we mean "add one"); since P=0, the next instruction byte was skipped. Try it with the instruction "11" or "14". Now what happens? You will have to believe me for now, that R1 or R4 was incremented. At the moment we cannot tell if it was or not. Later you can prove it in a better program.
INC r Increment register 1r ------------------------------------------------------------- Increment (add one to) the address register specified in the right digit of the instruction.Still in Program 3.10, try the opcode "20". What happened? Remember, if you keyed in the program correctly, all the instructions you know about result in some output when you push the "I" key. Or do they? Try IDL. Is 20 different from 00? If you wired up a Run/Stop light, you would see that with 20, the computer did not stop, but it still refused to go to the next instruction. (If you do not have a light to tell you when the computer stops, take my word for it; it didn't.) Suppose I tell you that the 20 instruction backs up R0 by one (we call this a decrement). Since R0 is also the PC, it now points to the same instruction again. The fetch cycle fetches the opcode and increments R0; the execute cycle decrements R0. It is stuck in a loop just as surely as if you had coded a branch that jumped to itself. Reset the computer and try it with "21" or "24". As you can see, you can't see what it did. We will come back to this later.
DEC r DECrement register 2r ------------------------------------------------------------- Decrement (subtract one from) the specified register.I will assume you have a vague notion about the operation of INC and DEC. Key in Program 2.3. How many instructions are there in this program that you have not yet met? Let's think about this program a little. Remember that R1 is 16 bits. That means that it can have any value between 0 and 65535. It also means that only half of it will fit into the accumulator (D) at a time. Suppose R1 is initially zero. As soon as you execute the INC R1 instruction it will be one, not zero. Look at it in binary:
I have not said much about instruction execution time (that is one of the topics of Chapter 7), but let me remark for this discussion, that each instruction in your ELF II requires 11 microseconds (except for those that have a left digit of "C", which require 16 microseconds). This means that the loop will go through once in about 70 microseconds, that is, it can repeat the loop about 15000 times per second. How does this compare with how often the Q light blinks? Think of it as a Monopoly game; every time R1 passes "GO" (in this case all zeros) Q blinks. Thus you can deduce that the zeros in R1 are probably making the accumulator zero. Take a guess at how long the Q light stays on. Does it seem more like 1/50th of a second than, say, one second or 1/15000th of a second? About how many times can your ELF go through the loop in 1/50th of a second? Would you believe 256? By now you should be ready to believe that the "91" opcode is copying the left half of R1 into the accumulator.
Just for fun, change the 91 to "81". Would you believe it is still blinking? Try stopping the computer (put it into the Wait state). Take a guess at how fast it is blinking now. Does it seem reasonable to you that there should be two instructions in the 1802; one for copying the left half of R1 into D and one for copying the right half? Try another experiment: Change the right digit in location 0000 to some other number (e.g. "9B") and also change the INC in location 0005 to increment the same register (i.e. make it "1B"). What happens if you change only one of them? Try some other numbers. Why does it not work for zero?
GLO r Get LOw byte of register 8r ------------------------------------------------------------- Copy the least significant eight bits of the specified register into D. GHI r Get HIgh byte of register 9r ------------------------------------------------------------- Copy the most significant eight bits of the specified register into D.You should also try changing the INC in Program 2.3 to a DEC. How does that affect the program operation? Try thinking of DEC as "un-INC". If you decrement a register containing all zeros, what is the result? I will say more about negative numbers in Chapter 5.
You may have guessed by now that the 1802 also lets you copy data from D into the address registers. Key in Program 4.1, and with the M/P switch on, run it.
.. PROGRAM 4.1 -- TEST PHI AND PLO .. 0000 6C INP 4 .. GET A COUNT 0001 BE PHI E .. ** 0002 7A REQ .. Q OFF 0003 2E DEC E .. DELAY: 0004 9E GHI E .. LOOK AT IT 0005 3A03 BNZ *-2 .. FALL THRU ON 00 0007 6C INP 4 .. DITTO, LO BYTE 0008 C4 NOP .. OR PLO E 0009 7B SEQ .. Q ON 000A 2E DEC E .. DELAY 000B 9E GHI E .. N COUNTS MORE 000C 320A BZ *-2 000E 3000 BR 0 .. REPEATNotice that it does not wait for the "I" key (EF4). Push various digit keys. See if you can see a relationship between the time to the next blink and the last two keys you pushed. (Hint: try "11" and "FF"). Now change the NOP in 0008 to "AE" and the "BE" in 0001 to a NOP ("C4"). Don't forget the M/P switch! How do the keys affect it now? Can you see a difference in the length of the blink? Try "11" then "FF". As you can see, opcodes "BE" and "AE" are changing the amount of the count in RE. You should know what is in D (from the INP 4 instruction, since you pushed the digit keys); does that seem to affect the timing of the program in a reasonable way? Are you ready to believe that these two instructions copy D into the two halves of register 14? If you are not yet sure, study the program some more. You see, it is not all that different (in principle) from Program 2.3. What happens if you key in "00"? Can you guess why?
PLO r Put D into Low byte of register Ar ------------------------------------------------------------- Copy D into the least significant eight bits of the specified register. PHI r Put D into High byte of register Br ------------------------------------------------------------- Copy D into the most significant eight bits of the specified register.Now you know how to set up an address register; but what is it good for? Well, maybe we can make the OUT instruction a little more useful. Key in Program 4.2:
.. PROGRAM 4.2 -- TEST SEX .. 0000 90 GHI 0 .. COPY R0 TO R8 0001 B8 PHI 8 0002 80 GLO 0 0003 A8 PLO 8 0004 3F04 WOW: BN4 * .. WAIT FOR "I" 0006 E8 SEX 8 .. ** 0007 64 OUT 4 .. OUTPUT TO DISPLAY 0008 C4 NOP .. SPACE FILLER 0009 3709 B4 * 000B 3004 BR WOW .. REPEATNotice that the first thing this program does is copy R0 to R8. What address do you think will now be in R8? Obviously, the whole program is in the first page (256 bytes) of memory, so you would expect the left half of R0 to be zero (remember that Reset puts all zeros into R0). What about the right half? No, it's not zero. R0 was zero before executing the first instruction; after fetching it, R0 was incremented to 0001. Let's try another one; what is the value of R0 when the GLO 0 instruction is executed (i.e. after it is fetched; think about the INP instruction as we have been using it). Before running this program, take a guess at what the output will be when you push the "I" key. Why was it not "C4" That's right, blame the new instruction, "E8". You will recall that the OUT instruction actually outputs the byte pointed to by the address register pointed to by X. Reset sets both X and P to zero, and we depended on that. Now, "E8" changed X to point to R8 (you know what was in R8, right?), so the OUT instruction used R8 instead of R0. Do you understand why you saw "A8"? Where is that byte in the program? Now guess what will happen when you push the "I" key again. Review the description of the OUT instruction in Chapter 3 again if you do not understand what happened. Which register is incremented by OUT? (Hint: what does X point to?) Now change the NOP in 0008 to a SEQ. Do you think this byte will be executed or skipped? Try it. Why does Q come on here but not if you run Program 3.8 with 7B in 0001 or 0008? Have you looked to see what X points to in each case? What does OUT do to that register? Which register does P point to? Experiment with different registers for the PHI, PLO, and SEX instructions. Can you figure out what happens if you use R0?
SEX r Set X Er ------------------------------------------------------------- Set register X to point to the specified register r.We know of one way to put data into the D register (the INP instruction); is there some way which does not inconvenience the operator (you) quite so much? Obviously there is. To see how it works, first sequence memory (i.e. run Program 2.2), then key in Program 4.3:
.. PROGRAM 4.3 -- TEST LDI .. 0000 90 GHI 0 .. SET PAGE 00 0001 B7 PHI 7 0002 F833 LDI #33 .. ** 0004 A7 PLO 7 .. LOW BYTE OF ADDRESS 0005 E7 SEX 7 .. SELECT FOR OUT 0006 64 LOOP: OUT 4 .. DISPLAY CONTENTS 0007 27 DEC 7 .. BACK UP R7 0008 3F08 BN4 * .. WAIT FOR "I" 000A 6C INP 4 .. GET KEYIN 000B 64 OUT 4 .. ECHO IT 000C 370C B4 * .. WAIT FOR RELEASE 000E 3006 BR LOOP .. REPEATRun this program and look at the display. What do you see? Where in memory do you suppose the 33 came from? Key some value into the hex keypad and push the "I" key; did your input show up on the display? Now release the "I" key and look again. Repeat this a few times so you know what the program is doing. Then reset the computer and examine memory. See if you can find where your inputs are stored. Now think about the program; which address register did the OUT and INP instructions use? (Hint: Look at the SEX instruction). Remember that when the computer executes a SEX, X continues to point to the specified address register until for some reason the computer changes the contents of X again. In this case you understand all of the instructions in the loop that follows the SEX, and there is no way out of that loop except resetting the computer. So all that time X=7. What is in R7? Notice at the beginning of the program that the program puts 00 into the left half of R7 (it got the 00 from the left half of R0). Recall also that the OUT instruction increments the address register (R7 in this case). Inside the loop there are two OUT instructions, and one DEC 7; that is two times R7 is incremented, and once it is decremented. What happens to R7 if you add one twice and subtract one once? Does this correspond to what you noticed the program doing? Finally, can you tell what was in R7 at the beginning of the loop? Clearly it must depend on whatever is in D when the 1802 executes the PLO 7 instruction, but what is it? Do you see a correspondence between the second byte of the LDI instruction and the starting value of R7? Convince yourself that it is not a relationship with the previous contents of memory by running the program again. This time what is displayed? Does it remind you of what you previously keyed in? Change the byte in location 0003 to something else and try it again. When the data that the instruction uses (in this case, that it loads into D) is immediately following the opcode, we call it the Immediate addressing mode.
LDI b Load D Immediate F8 bb ------------------------------------------------------------- Copy the second byte of the instruction into the D register.Now that we know how to put specific addresses into an address register, things will be a little easier to test. In Program 4.4 we set up two address registers with different values. One of them we will use for inputting data; the other will demonstrate the next instruction. First sequence memory, then key in Program 4.4:
.. PROGRAM 4.4 -- TEST STORE .. 0000 90 GHI 0 .. SET UP R6 AND R7 0001 B6 PHI 6 0002 B7 PHI 7 0003 F833 LDI #33 .. DISTANCE IN RAM 0005 A6 PLO 6 0006 F81E LDI #1E .. CLOSE FOR EASY LOOK 0008 A7 PLO 7 0009 3F09 LOOP: BN4 LOOP.. WAIT FOR "I" 000B E6 SEX 6 .. INPUT A BYTE 000C 6C INP 4 000D 370D B4 * .. WAIT FOR RELEASE 000F 26 DEC 6 .. MOVE OFF INPUT 0010 57 STR 7 .. ** 0011 3009 BR LOOP .. REPEATThere is only one instruction here you have not yet met. Ignoring that, what would you expect the program to do? Notice there are no OUT instructions, so you cannot expect the display to change. Run it, and key in a few numbers, remembering what you enter. Now reset the computer and look at memory. What is in memory location 001E? Why should it be the last number you keyed in instead of the "1E" that the sequencer put there? Look also at the few bytes before location 0033; do they correspond to what you expected the program to do? If not, think through the program again. Notice that after each input, R6 was decremented. Now change the 57 in location 0010 to a 56. Before you run the program again, see if you can guess what will be different. Try it. Were you right? Did you notice that the memory R7 points to is now unchanged, but the memory R6 points to is now the same as what was last input? Change the DEC 6 instruction to INC 7, and put the 57 back in 0010 (i.e. put 17 in 000F, 57 in 0010) and run it again. When you examine memory this time, what is it you see near 001E (I hope you saw a sequence of input bytes)? Do you think you understand the STR instruction?
STR r SToRe D into memory 5r ------------------------------------------------------------- Using the specified address register, store (copy the contents of) the accumulator into memory.The 1802 has two store instructions. The second one is a little tricky to understand. Resequence memory, and put Program 4.4 back in, but this time change the STR instruction to a hex "73". Run the program and examine the part of memory near location 0033. How does it differ from what you expected? Change the DEC 6 to a SEX 7 (hex E7 in 000E) and run it again, but be careful not to enter more than 5 or 6 data bytes. Where did the data show up? Do you see a relationship this time between R7 and where the data was stored? What can you guess about which address register the 73 opcode uses? Does anything special happen to that register? Compare this to the STR instruction; did it change its address register? If you are not sure you know what happened, read the instruction summary for STXD (below) and review the program again.
STXD STore D via R(X) and Decrement R(X) 73 ------------------------------------------------------------- Store the accumulator into the memory location pointed to by the address register pointed to by X, then decrement that address register.As you might have guessed, when a computer has an instruction to copy data from one kind of memory to another, it usually also has an instruction to copy data in the other direction. The opposite direction from a Store is a Load, and you have seen one of these already (LDI). Let's look at a few others. Program 4.5 is a little larger than the others, but we hope to make it do the work of two or three. First sequence memory, then key in Program 4.5:
.. PROGRAM 4.5 -- TEST LOADS .. 0000 90 GHI 0 .. SET UP R8 AND R9 0001 B8 PHI 8 0002 B9 PHI 9 0003 F880 LDI #80 .. R8=0080 0005 A8 PLO 8 0006 F890 LDI #90 .. R9=0090 0008 A9 PLO 9 0009 E9 AGAIN:SEX 9 000A 7B SEQ .. ANNOUNCE US 000B 3F0B BN4 * .. WAIT FOR INPUT 000D 6C INP 4 .. GET OPCODE 000E 64 OUT 4 .. SHOW IT 000F 7A REQ 0010 50 STR 0 .. STORE INTO PROGRAM 0011 C4 NOP .. EXECUTE IT HERE 0012 29 DEC 9 .. POINT TO SCRATCH 0013 59 STR 9 .. STUFF D THERE 0014 3714 B4 * .. WAIT FOR RELEASE 0016 64 OUT 4 .. SHOW DATUM 0017 29 DEC 9 .. NOW 0018 88 GLO 8 .. SHOW R8, 0019 59 STR 9 001A 3F1A BN4 * .. AT THE SIGNAL 001C 64 OUT 4 .. SHOW DATUM 001D 89 GLO 9 .. SHOW R9, 001E 29 DEC 9 .. NOW, 001F 59 STR 9 0020 3720 B4 * .. AT THE SIGNAL 0022 64 OUT 4 .. SHOW DATUM 0023 3009 BR AGAIN.. REPEATBefore running this program, look at it carefully and be sure you understand exactly what it will do. There are no instructions that you have not met. There are, however, a few tricky spots. At location 0010 there is a STR 0; what do you think is in R0 when this instruction is executed? (Remember, R0 is the PC, which points to the next instruction). What will happen to the NOP in 0011? What will be the next instruction to be fetched (and executed)? Think: does STR change its address register? If R0 points to 0011 before the STR is executed, then R0 also points to 0011 after the STR is executed, but before the next instruction is fetched. How does this compare with Program 3.9 and 3.10?
Turn on the M/P switch the first time you run this program, just so you can get a feel for its operation. Notice that nothing you key in has any effect, since memory is protected. Get comfortable with what happens as you push the "I" key: First Q comes on, and it waits for the "I" key; when you push it, Q goes off, and the display shows what you keyed in (but of course, since memory is protected, you only see the previous contents of 0090, which is 90); when you release the "I" key, you see the results in D of executing the opcode that was input (or in this case, the previous contents of 008F); when you push the "I" key again it tries to display the right half of R8, then R9 when you release it, both in the same memory location. (If I seem to dwell excessively on understanding what the programs are doing, it is because you cannot expect to write computer programs if you cannot understand what a program is doing.)
Now reset the computer, turn off M/P, and run it again. First key in "C4" (NOP), and push "I" twice slowly. Do you understand why you see what is on the display? Without keying in any new datum, push "I" twice again. Notice that R8 does not change, but R9 is incremented. Now key in "19" (INC R9), and watch it. Try "18" (INC R8), "29" (DEC R9), and "28" (DEC R8). Since you understand these instructions already, you should be able to follow what you see. Try "73" (STXD). Try GHI and GLO for various registers: what is in the registers you have not been using? What happens with PLO 9 or PLO 8? Now that you have clobbered your registers, Reset the computer and Run again. Before trying it, try to analyze what will happen when you key in "F8" (LDI). Remember LDI is a two-byte instruction; what is the second byte? What did that do to R9? If "29" is the second byte of an LDI at location 0011, do you understand why it is not executed as a "DEC 9"?
Once you are convinced you understand how this program works, and you have tried some of those previous instructions that you did not exactly understand (I hope it helped to run them through this program), you are ready to try some new opcodes. Key in "48". What happened to R8? Did this remind you of the INC 8 instruction? How about D? Do you know what was in memory where R8 pointed? Perhaps it would help to resequence memory, and put Program 4.5 back in, so that you know exactly what is in memory; that is a choice up to you, if you feel unsure about what this opcode did. Remember, the only way you can be sure you know what an instruction did is to know what the complete state of the computer was both before and after executing it. Now try "49". How is this different from 48? Try "40". Do you know what happened? If not, compare it to LDI ("F8").
LDA r Load D and Advance 4r ------------------------------------------------------------- Copy the contents of the memory byte pointed to by the specified address register r into the Accumulator, and increment the register.Still using Program 4.5, try keying in "08" and "09". How is this different from the LDA instructions 48 and 49? Is "00" different from 40 in the same way? What happens when you try it? You do remember that 00 is IDL, don't you?
LDN r Load D via N (r = 1 to F) 0r ------------------------------------------------------------- Copy the memory byte pointed to by the specified address register r into the Accumulator.Now try three other opcodes in Program 4.5: "60", "F0", and "72". How do these compare respectively with INC 9, LDN 9, and LDA 9? What is in X at the time these opcodes are executed by the computer? Does this suggest how these might be related to X? Can you think of some way to modify Program 4.5 to see if your guess is correct?
IRX Increment R(X) 60 ------------------------------------------------------------- Increment the register pointed to by X. LDX Load D via R(X) F0 ------------------------------------------------------------- Load the accumulator from the memory byte pointed to by the address register pointed to by X. LDXA Load D via R(X) and Advance 72 ------------------------------------------------------------- Load the accumulator from the memory byte pointed to by the address register pointed to by X, then increment that register.Now you have a good understanding of the register operations in the 1802. This includes all opcodes with a left digit of 0, 1, 2, 4, 5, 8, 9, A, B, and E, as well as the opcodes 60, 72, 73, F0, and F8. In the next chapter we will use them to help us study the arithmetic and logical instructions.
When you were in grammar school, you added two numbers (say 43 + 25) one digit at a time, starting from the right: 3+5=8; 4+2=6; result = 68. Now you know that 3+5=8, but when you were first learning how to add, you had to memorize a big addition table. Exactly the same kind of process goes on when your computer adds, except that its table is for binary numbers, not decimal, and looks like this:
+ | 0 1 0 | 0 1 1 | 1 10Your ELF II, however, does not let you look at the binary numbers directly, so it helps to imagine that the addition table that the computer has memorized is actually for hexadecimal, not binary. It turns out to have the same results. I will not reproduce the hex addition table here.
Subtraction works by the same principles as addition, as you will recall from way back when. But if you try to subtract a larger number from a smaller number, things get a little tricky. I think the best way to introduce you to most of these problems is by seeing what the computer actually does.
If you want your computer to multiply or divide, you are almost out of luck. The 1802 and most other 8 bit microprocessors can only multiply or divide by two. The operation is called a shift. If you shift a number left by one bit position, you have doubled it (i.e. multiplied it by 2). Similarly, shifting a number right one bit position divides the number by two. More on this later.
There are three logical operations which most microprocessors can do with a single instruction. They operate on the individual bits (remember, one bit is a single true-false answer) in the computer words (or bytes). I will give you the tables now, so you can compare these operations to the instructions later.
AND| 0 1 0 | 0 0 1 | 0 1 OR | 0 1 0 | 0 1 1 | 1 1 XOR| 0 1 0 | 0 1 0 | 1 0Now key in Program 5.1. As you can see, it requires three inputs; an opcode, which is executed at location 0029, and two data bytes, one stored in location 0060 (via R6) and one stored in location 0061 (same address register, but incremented). It does its operation, then puts the result back into location 0060 to display it. If the result is zero, the program also turns Q on. So that you will know which input is expected, the display will show "00" when it is waiting for an opcode, "01" when waiting for the first operand, and "02" when waiting for the second operand. After it performs the operation, the result also becomes the first operand of the next time through the loop, so you only have to key in the second operand for each successive time through. Of course, any time you want to put a new opcode or first operand, you can reset the computer and run the program again. Look over the program and be sure you understand it. Notice that it contains only instructions you have met in Chapters 3 and 4.
.. PROGRAM 5.1 -- TEST ALU OPS .. 0000 90 GHI 0 .. SET UP R6 0001 B6 PHI 6 0002 F829 LDI DOIT .. FOR INPUT OF OPCODE 0004 A6 PLO 6 0005 E0 SEX 0 .. (X=0 ALREADY) 0006 6400 OUT 4,00 .. ANNOUNCE US READY 0008 E6 SEX 6 .. NOW X=6 0009 3F09 BN4 * .. WAIT FOR IT 000B 6C INP 4 .. OK, GET IT 000C 64 OUT 4 .. AND ECHO TO DISPLAY 000D 370D B4 * .. WAIT FOR RELEASE 000F F860 LDI #60 .. NOW GET READY FOR 0011 A6 PLO 6 .. FIRST OPERAND 0012 E0 SEX 0 .. SAY SO 0013 6401 OUT 4,01 0015 3F15 BN4 * 0017 E6 SEX 6 .. TAKE IT IN AND ECHO 0018 6C INP 4 .. (TO 0060) 0019 64 OUT 4 .. (ALSO INCREMENT R6) 001A 371A B4 * 001C E0 SEX 0 .. DITTO SECOND OPERAND 001D 6402 OUT 4,02 001F E6 SEX 6 0020 3F20 LOOP: BN4 * .. WAIT FOR IT 0022 6C INP 4 .. GET IT (NOTE: X=6) 0023 64 OUT 4 .. ECHO IT 0024 3724 B4 * .. WAIT FOR RELEASE 0026 26 DEC 6 .. BACK UP R6 TO 0060 0027 26 DEC 6 0028 46 LDA 6 .. GET 1ST OPERAND TO D 0029 C4 DOIT: NOP .. DO OPERATION 002A C4 NOP .. (SPARE) 002B 26 DEC 6 .. BACK TO 0060 002C 56 STR 6 .. OUTPUT RESULT 002D 64 OUT 4 .. (X=6 STILL) 002E 7A REQ .. TURN OFF Q 002F CA0020 LBNZ LOOP .. THEN IF ZERO, 0032 7B SEQ .. TURN IT ON AGAIN 0033 3020 BR LOOP .. REPEAT IN ANY CASEWhen you first run this program, try entering "C4", "11", "22", then "33". Notice that after the first time through, the only display is the "11" alternating with your input. If you run it again, entering "00" instead of "11", you will notice that Q comes on and stays on. The program loads the first operand into D, executes the NOP you keyed in, then displays the contents of D (which has not changed).
Restart the program, but this time enter an opcode of "F0" (LDX). Now what data is displayed? Be sure you understand what you are seeing for the NOP and the LDX entered into this program before proceeding any further. It is essential to have a good feeling for the prior contents of D (the accumulator) and the byte in memory that the address register pointed to by X points to; the NOP shows you the former, LDX shows you the latter. The ALU (Arithmetic and Logical Unit) instructions combine these two data bytes to give some result; if you do not know what the operation starts with, you will not know how it got its answer. Notice however, that the first time through they are your inputs; after that they are the previously displayed result and the next input, respectively.
Now you should be ready to try a new opcode. Start with "F1", followed by "33", then "55". What was the result? Does repeating the operation with the same second operand (i.e. push the "I" key again) change the result? Try giving it "01". Can you figure out how to get a result of "FF"? Can you figure out which operation this opcode does (ADD, AND, OR, or XOR)? (Hint: try giving it 00,00; 00,01; 01,00; and 01,01 and then compare the results to the four tables I gave you).
OR Logical OR F1 ------------------------------------------------------------- The datum in D and the datum in the memory byte pointed to by the address register pointed to by X are combined in a bit-by-bit inclusive OR, and the result is left in D.Try the same experiments with the opcode "F2". Can you figure out how to get a result of "FF"? Have you figured out which operation this is?
AND Logical AND F2 ------------------------------------------------------------- The datum in D and the datum in the memory byte pointed to by the address register pointed to by X are combined in a bit-by-bit logical AND, and the result is left in D.There is one more logical operation you have not yet tested. Try opcode "F3". Notice that repeated operations with the same datum in the second operand is not the same as for AND and OR. Do you see a pattern?
XOR eXclusive OR F3 ------------------------------------------------------------- The datum in D and the datum in the memory byte pointed to by the address register pointed to by X are combined in a bit-by-bit exclusive OR, and the result is left in D.It might help you to understand how these instructions are used if you consider them in the following way:
AND forces to zero those bits in the accumulator which are zeros in the second operand.
OR forces to one those bits in the accumulator which are ones in the second operand.
XOR complements (sets zeros to ones, ones to zeros) those bits in the accumulator which correspond to ones in the second operand, leaving the other bits in the accumulator unchanged.
Also, XOR forces to zero those bits in the accumulator which match the corresponding bits of the second operand, and forces to one those bits which do not match.
We have met before (in the branches and the I/O instructions) a family of opcodes with "positive" and "negative" versions, distinguished by a single bit. The ALU opcodes are something like them, but the bit distinguishes the Immediate addressing mode (two byte instruction, with the operand being the second byte) from the "R(X)" or register indirect addressing mode (the datum is in memory, an address register points to it; in the 1802 ALU operations that address register is selected by X). Consider the difference between LDX (F0) and LDI (F8). Try LDI in Program 5.1. What datum is displayed as a result? Where in memory did it come from? (Hint: look at "the second byte of the instruction"). When you have a good feeling for the difference, you are ready to try "F9". Does the bit pattern of the opcode give you a clue at to what to expect? Was your guess right?
ORI b OR Immediate F9 bb ------------------------------------------------------------- All the bits in D corresponding to ones in the second byte of the instruction are set to ones.Try also "FA" and "FB".
ANI b ANd Immediate FA bb ------------------------------------------------------------- All the bits in D corresponding to zeros in the second byte of the instruction are set to zeros. XRI b eXclusive oR Immediate FB bb ------------------------------------------------------------- All the bits in D corresponding to ones in the second byte of the instruction are complemented.Now you are ready to try the opcode "F4". For the first two operands, use something like "12" and "34". Obviously the result is the sum of these. Then enter a larger number like "58". Is the result what you expected? Remember your computer adds in binary (or hexadecimal), not the familiar decimal. Look at the sum in binary:
binary hex 0100 0110 46 +0101 1000 +58 1001 1110 9ENotice that 6+8 (which is 0110 + 1000) is 14, but 14 decimal is 1110 binary, which is E in hexadecimal. Do you understand why 4+5=9? Notice here that the second bit sum from the left is 1+1, which our table tells us is 10 (in binary). So the sum is 0 with a carry into the next digit to the left. Before you enter it, try to anticipate what adding "27" will result in. Start your paper sum with the rightmost bit, which is 0+1=1. The next bit sum is 1+1; what digit do you write down? What carry? The third digit is trickier: 1+1+carry=? Our addition table does not show what to do with three ones, but your recollection from grammar school should remind you that 1+1+1=3 which is 11 in binary. In other words, write 1, carry 1. Finish the sum, then try entering the number. Did the computer get the same result you did? If not, do you know what you did wrong? (Notice that I assume the computer's answer is the correct