Apple Cart. (column) Steve Prescott.
Are you interested in high-resolution graphics? Would you like to be able to change all the colors on either of the hi-res screens automatically? Are you perhaps even slightly interested in (dare I say it) machine language? If you can answer yes to any of these questions, I'm sure you will be interested in the short program that follows. The program is called Farbe Flipper, and by taking a mere fifteen minutes to type it in now you will gain an easy yet powerful graphics utility for life.
You may be wondering why I chose the name Farbe Flipper. "Flipper' you understand, but "Farbe?' Let me give you a hint: don't even try looking it up unless you happen to have a German dictionary around, because Farbe is the German word for color. All right, now that we've cleared the first obstacle, let's attempt to understand the important thing: the program.
Memory: What is a Byte?
Part of Farbe Flipper is, as I have hinted, written in machine language and, as the program is going to work with the actual little memory "boxes' in which pictures are stored, it seems in order to try to understand just how the Apple saves a picture.
The first thing you should know is how information is stored in a computer. There are small packets of information called bytes, and inside each byte are eight smaller packets called bits. As the name implies, a bit is a very small piece of information. It is either a one or a zero. A typical byte, therefore, would look something like this:
Now that you know how information is stored, let's look at how the Apple uses these little packets to store a picture.
Hi-Res Graphics: Bit-by-Bit
What I will discuss here is also explained on pages 19 and 20 of the Apple II Reference Manual, but I will provide a slightly more detailed explanation.
If you have ever programmed in Basic, you may know that there are two hi-res screens (HGR, HGR2). Inside the Apple, there are actually two totally separate places in which these pictures are stored. The first or primary page starts at the ghastly number of 8192 and goes to 16,383: the second or secondary page starts at 16,384 and continues up to 24,575. At first glance, these numbers can be quite intimidating, but they are actually addresses just like your house number, and a picture on the screen is stored in a series of bytes between the beginning and ending addresses.
"Wait a second,' you may say, "the picture is stored there? Uh . . . did I miss something?' No, don't worry, I'm getting to that part. The above numbers are nice to know, but there is a much easier way to remember them, and luckily in machine language we can use the easier way.
The easier way is in hexadecimal (base 16). Take 8192, for example: In hexadecimal, 8192 is equal to $2000, and that is a great deal easier to remember. The dollar sign is there to remind you the number is in hexadecimal. Figure 1 is an easy-to-use chart for all the important hi-res addresses:
Page 1 Start: 8192 $2000 End: 16,383 $3FFF
Page 2 Start: 16,384 $4000 End: 24,575 $5FFF
What follows is a much simplified explanation of the color switching process, but it is adequate for my purpose. A byte, as I said, has eight bits, and for hi-res graphics each of seven of the eight bits represents one point on the hi-res screen. The eighth bit is used to select which color the points will be.
To change the colors on the screen, all we have to do is switch all the ones to zeros and all the zeros to ones inside a hi-res byte. This is done with an EOR or Exclusive-OR instruction. What an EOR does is compare two bits, and if neither of them is equal to one or if both are equal to one, the answer is equal to zero, but if only one of them is equal to one, the answer is also equal to one. This is concisely summarized in the following truth table:
What is important is that whenever you EOR a bit with a one, it will change to the opposite state; ie., a one will change to a zero, and a zero will change to a one. Now you just extend that 0300- A9 00 LDA #$00 we can EOR our byte with 11111111, which in hexadecimal is $FF. For example, if I EOR our sample byte, I get:
Notice that the result is the opposite of the sample byte, just as we thought it would be. Once you understand this concept, you have the key to the entire Farbe Flipper program.
The machine language program which uses the color-switching process described above is a fairly straightforward yet useful introduction to a low level language. I will go through the program one line at a time and explain each one.
0300- A9 00 LDS #$00
LDA #$00 means LoaD the Accumulator with the number zero. The accumulator is really just a machine language variable, so a comparable Basic statement would be 300 A=0
0302- 85 1A STA $1A
STA $1A means STore the Accumulator in memory location $1A. The dollar sign, remember, signifies hexadecimal, and the first two lines are really putting a zero into $1A so that we can use it later.
0304- A9 20 LDA #$20
LDA #$20 means LoaD the Accumulator with the number 20. The zero which had been in the accumulator is automatically erased when the 20 is loaded.
0306- 85 1B STA $1B
STA $1B means STore the Accumulator which is now equal to #$20 in location $1B, which is the location immediately following the one in which the zero was stored. After these first four instructions, memory locations $1A and $1B would be as follows:
The way we are going to change the color of every point on the screen is by EORing each byte with #$FF, but we need some way of telling the Apple which byte we want to change. To go through the memory byte-by-byte, we will use indexed indirect addressing. What this does is not actually address each byte individually, but rather address it by how far away it is from the beginning of a block of memory.
The #$00 and #$20 that we put into $1A and $1B were the beginning pointers, except that they are backwards. (They have to be for indexed indirect addressing.) If you reverse the numbers and put them together, you get #$2000, which should look familiar as it is the beginning of the primary hi-res graphics screen.
Okay, let's see if we understand everything so far: to change the color of every point, we are going to EOR each byte with #$FF. In order to EOR each byte, however, we must address it (find it), and for that we use indirect indexed addressing.
The addressing method has two parts, the beginning pointers and the offset pointer. The beginning pointers must be stored backwards in the zero page (the beginning of the Apple's memory), and we did that by storing #$00 and #$20 in $1A and $1B respectively. Okay, but what about the offset pointer? I hope that is what you are wondering, because that is what we are going to do right now.
0308- A0 00 LDY #$00
LDY #$00 means LoaD the Y register with the number zero. The Y register is another machine language variable, just like the accumulator, so a comparable Basic statement would be 308 Y=0
In this program, we will use the Y register as the offset pointer, as you will see right now.
030A- B1 1A LDA ($1A), Y
LDA ($1A), Y finally uses the indirect indexed addressing to LoaD the Accumulator. It loads the accumulator with the byte whose address is the numbers in $1A and $1B plus the Y register. For example, right now $1A and $1B are $2000 and the Y register is #$00, so:
$2000 (beginning pointer) + #$ 00 (offset pointer)/$2000 (result: byte to be loaded)
and the accumulator will be loaded with the information in byte $2000. Now that we have the hi-res byte, let's change the colors.
030C- 49 FF EOR #$FF
This is the basis of the entire program, and as I have shown, it changes every bit in the accumulator to the opposite state. Now that the byte is changed, all that remains is to store it back in its place and get the next byte.
030E- 91 1A STA ($1A), Y
STA ($1A), Y means Store the Accumulator in the byte whose address is the numbers in $1A and $1B plus the Y register. Since neither $1A, $1B, nor the Y register has been changed since the byte was loaded, the contents of the accumulator are put back exactly as they were found, except that now the byte is exactly the opposite of what it originally was. What the remainder of this program does is change the pointers so that a new byte is loaded into the accumulator each time.
The main way of loading successive bytes is by incrementing (adding one to) the Y register, but this has a significant limitation: the largest number the Y register can hold is #$FF, and that is not nearly enough of an offset to access the entire hi-res page. The way to solve this, therefore, is to INCrement the beginning pointers ($1A and $1B) and keep the offset pointer (Y register) equal to zero. Here it is:
0310- E6 1A INC $1A
INC $1A means INCrement memory location $1A, so in our case $1A would change from zero to one. If we switch the order of $1A and $1B, we get the number $2001, which is the next byte of the hi-res screen and therefore the next byte we want to change.
0312- DO F6 BNE $030A
BNE $030A means Branch if the last arithmetic operation did Not Equal zero to the line which begins at $030A. You may wonder how adding to a positive number would ever result in zero. Just like the Y register, any memory location can hold a number only up to #$FF, and when #$01 is added to #$FF, the Apple automatically makes it a zero.
In our program, therefore, the beginning pointer history would look like this: $2000, $2001, $2002, . . ., $20FF, $2000. This is not what we want, for you notice that in the end we begin to repeat, changing bytes that we already have changed, and we never get to any of the memory above $20FF. Therefore, BNE $030A means that if, when you add #$01 to $1A, you get a whole number, go to line number $030A. But if you get a zero, you drop down to the next line where the problem will be handled.
0314- E6 1B INC $1B
INC $1B means INCrement memory location $1B. In normal (base 10) arithmetic, if you add one to 99, you get
Our program is doing the same sort of thing, only it is in hexadecimal. F is the hexadecimal equivalent of 15, so it is the largest possible one-digit number in base 16, just as 9 is the largest possible one-digit number in base 10. Therefore:
#$FF + #$01/#$100
What INC $1B does is add one to the first half of the pointer whenever the second half has reached its limit. The last byte in which we want to switch the colors is $3FFF, the end of HGR, so now we will check to see if the next byte to be changed is $4000; and if it is, we want to stop.
0316- A5 1B LDA $1B
LDA $1B means LoaD the Accumulator with the number in memory location $1B. It does not mean Load the Accumulator with the actual number #$1B, and the difference is that the LDAs in lines $0300 and $0304 have number signs (#) before the numbers.
0318- C9 40 CMP #$40
CMP #$40 means CoMPare the accumulator with the number #$40. To compare it, the Apple really subtracts #$40 from the accumulator. The answer is not stored anywhere, but certain flags are set that we can check to see what happened when the subtraction took place.
031A- DO EE BNE $030A
BNE #030A means Branch if the subtraction did Not Equal zero to the line at $030A. In almost all cases, the program at this point will go to $030A, but when $1B is equal to #$40, the entire hi-res screen will have been switched, and the program will drop down to the next line.
031C- 60 RTS
RTS means ReTurn from the Subroutine. This entire machine language program is really just a subroutine or a program within a program, so after this part is finished, we want to return to the other section. What will actually happen is that we will, in effect, jump back into the Basic program.
So there it is--a brief, yet complete Apple machine language program that you can understand. You may wonder what the two-digit numbers are between the line numbers and the instructions: those are OP-codes, numbers that the Apple uses internally to store your program. To type in this program, it is actually easier to use these OP-codes. Just type:
*300: A9 00 85 . . . EE 60 (RETURN)
You can actually type the entire program (all the OP-codes) in on one line, as long as you remember to leave one space between each two-digit number.
Back to Basic
The Basic program printed here is a short driver routine for the machine language subroutine we just analyzed and is divided into three main sections:
In line 50 you see a long string of numbers in a DATA statement. These numbers are the decimal (base 10) equivalents of the OP-codes that you used to type in the machine language program, and by READing them and POKEing them into memory, this Basic program writes the machine language subroutine for you.
If, for you own programs, you just want the machine language subroutine, you can merely type in lines 50-90, and the routine will be accessible with the ampersand (&). What line 90 does is tell the computer where to jump when you use the ampersand, and by POKEing 00 and 03 (0 and 3), you are telling the computer to go to $0300. (Yes, you must reserve them again.)
The next section of the program is the menu or list of options, and it is fairly self-explanatory. PG is a variable telling which page is presently being used. If PG=1, option one is printed in inverse, but if PG=2, option two is printed in inverse. Line 240 GETs your choice (CH$ ), and lines 250-290 analyze it.
The subroutine starting at line 300 displays the screen, and the series of POKEs in line 310 is a way of showing the hi-res screen without destroying the contents using the "soft-switches' described on page 13 of the Reference Manual.
Starting at line 340, the actual color changing takes place. Because the Apple has two hi-res graphics screens, Farbe Flipper must know which one you want to use. You may remember that in the beginning of the machine language subroutine we saved a #$20 for page one (the first hi-res screen); for page two the beginning is #$40, and we want to stop when the next byte will be $6000.
Lines 360 and 370 of the Basic program enter the correct values: if you are working on page one, the program POKEs in 32 (#$20 in hexadecimal) as the beginning address and 64 (#$40 in hexadecimal) as the ending address. If you are working on page two, the program POKEs in 64 and 96 (#$60 in hexadecimal). Line 380 may look strange, but this is what ties the machine language subroutine and the Basic program together. In a way, it is saying, "Okay, you know which screen we are using now, so go ahead and change the colors.'
Now that you know how Farbe Flipper works, have fun with it, play with it, even change it if you want. To save the Basic program, type:
SAVE FARBE FLIPPER
and if you want to save the machine language subroutine separately (you don't have to), type:
BSAVE FARBE FLIPPER. CODE, A$300, L$1E
If you use another program that makes a neat picture, and you would like to change it, you can load Farbe Flipper without hurting either of the hi-res screens in any way. I have tried to make this program as compact as possible, but if you think you can improve it, go ahead. The best way to learn is by experimenting, and I would be happy to hear about how you changed and improved this printed version.
Table: Listing 1.
Table: Listing 2.