TinyELF

Chapter 4 - Register Operations

When I introduced the 1802 in Chapter 2, I mentioned that it had 16 general-purpose registers. In this chapter you will see how to manipulate these registers. So far we have used only R0 since Reset forces P and X both to point to R0. I am going to have to presume on your patience just a little for the first few instructions we study in this chapter: Since R0 is the only register we know anything about, we will try out some of the new instructions on R0. This will necessarily leave you with a little bit of an empty feeling, since you will not yet have a good feel for the power of these instructions. Bear with me, and you will become more comfortable with them as you see them used in the later examples.

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:

00000000 00000000 initially
00000000 00000001 after increment

Notice that most of the register is still zero. In fact, the whole left half is zero, even if you increment it again:

00000000 00000010

How many times can you increment it before the left half is not zero? Here is what it looks like after 255 increments:

00000000 11111111

The next increment takes it to

00000001 00000000

How about after 511 increments (in all)? You see, after each 256 increments, the left half goes up one. How many increments will be required to take the left half up to all ones? Would you believe that it takes 65535 (=255x256+255) increments to go from all zeros to all ones? Then what happens? It takes only one increment to go from all ones to all zeros. Notice however, that for 65280 of the 65536 increments that it takes to go from all zeros back to all zeros, the left half of the register is not zero. Now look at Program 2.3 again. If the accumulator is zero, the LSZ instruction will skip over the REQ and the SKP and execute the SEQ: the Q light comes on. But if the accumulator is not zero, the LSZ falls through to execute the REQ (turning Q off) and the SKP (which skips over the SEQ). Since the Q light obviously blinks, you have to assume that sometimes the accumulator is zero, and sometimes it is not.

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   .. REPEAT

Notice 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.

        ..  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  .. REPEAT

Notice 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 .. REPEAT

Run 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 .. REPEAT

There 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.. REPEAT

Before 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.

[ << Chapter 3 ] [ Index ] [ Chapter 5 >> ]



* (A Short Course In Programming is Copyright 1980 by Tom Pittman, and is reproduced in TinyELF's help book with the author's permission. Visit Tom's website.)