So can we use DHR page 2 or what?
While I didn't touch on it in my earlier post, there is more than one way to access AUX memory, and therefore the DHR pages. We have already talked about using the 80STOREON softswitch $C001 to change the function of the PAGE1/PAGE2 softswitches so they map $2000-$3FFF (hi-res page 1) between MAIN and AUX memory banks respectively. The effect of which you can see here:
One limitation you might notice is that, for whatever reason (remember that DHR was an afterthought) these switches ONLY work for hi-res page 1. In other words even with 80STOREON and PAGE2 selected, hi-res page 2 ($4000-$5FFF) still maps to main memory.
So what do we do? Well first we will use another softtswitch 80STOREOFF $C000 this returns the PAGE1/PAGE2 function to normal. Once we do that we can use a different set of softswitches: RAMWRTON ($C005) and RAMWRTOFF ($C004) to allow us to write to AUX memory.
These switches act in a fundamentally different way from what 80STOREON gives us. When $C005 is invoked all memory WRITE operations (e.g. STA $2222) go to AUX memory and when $C004 is invoked all memory WRITE operations go to main memory. READ operations (including fetching the next instruction in your program) always go to MAIN memory.
In this configuration we can use the PAGE1/PAGE2 softswitches to display the DHR pages 1 and 2 respectively.
To demonstrate this I've provided a program below. It stores alternating black (bit pattern 0000) and then white (bit pattern 1111) pixels in the first position of the first eight lines of DHR PAGE1. Which starts at AUX memory location $2000. From there we store the opposite pattern, white and then black on DHR PAGE2. Which is at AUX memory location $4000. Finally we enter into a loop which just flips endlessly between PAGE1 and PAGE2.
First we have the assembly code:
STA $C050 ;Turn on GRAPHICS STA $C057 ;Turn on Hi-res STA $C052 ;Turn on Full screen STA $C05E ;Turn on DHR STA $C00D ;Turn on 80 Columns STA $C000 ;Turn OFF 80STORE STA $C005 ;Turn ON RAMWRT LDA #$00 ;Load bitpattern 000000 STA $2000 ;Store on DHR PAGE 1, line 1 STA $4400 ;Store on DHR PAGE 2, line 2 STA $2800 ;Store on DHR PAGE 1, line 3 STA $4C00 ;Store on DHR PAGE 2, line 4 STA $3000 ;Store on DHR PAGE 1, line 5 STA $5400 ;Store on DHR PAGE 2, line 6 STA $3800 ;Store on DHR PAGE 1, line 7 STA $5C00 ;Store on DHR PAGE 2, line 8 LDA #$0F ;Load bitpattern 001111 STA $4000 ;Store on DHR PAGE 2, line 1 STA $2400 ;Store on DHR PAGE 1, line 2 STA $4800 ;Store on DHR PAGE 2, line 3 STA $2C00 ;Store on DHR PAGE 1, line 4 STA $5000 ;Store on DHR PAGE 2, line 5 STA $3400 ;Store on DHR PAGE 1, line 6 STA $5800 ;Store on DHR PAGE 2, line 7 STA $3C00 ;Store on DHR PAGE 1, line 8 LOOP STA $C055 ;Show PAGE 2 STA $C054 ;Show PAGE 1 JMP LOOPI'll assume, for now that everyone understands the insane VERTICAL structure of all the Apple II hi-res screens. If you don't then just take it for granted that each line of pixels in the first eight lines of either DHR page are $400 bytes apart. Anyone who wants a tutorial on this just mention it the comments section!
Now here's the program in binary form. You can paste it into your favorite emulator.
call -151
6000: 8d 50 c0 8d 57 c0 8d 52 c0 8d 5e c0 8d 0d c0 8d 00 c0 8d 05 c0 a9 00 8d 00 20 8d 00 44 8d 00 28 8d 00 4c 8d 00 30 8d 00 54 8d 00 38 8d 00 5c a9 0f 8d 00 40 8d 00 24 8d 00 48 8d 00 2c 8d 00 50 8d 00 34 8d 00 58 8d 00 3c 8d 55 c0 8d 54 c0 4c 46 60
6000g
So why would we ever use 80STOREON?
Virtually every graphic mode on every computer involves trade-offs. 80STOREON is no different. When 80STOREON is active we can read and write from DHR PAGE1. When 80STOREOFF is invoked RAMWRT only lets us WRITE to DHR PAGE1 and PAGE2. If we wanted to read the screen we would be out of luck. This would be problematic if, for example you were drawing a spaceship on a complicated background. In this case it would be common to copy the small part of the background you are going to draw the ship on top of to some area in memory. That way, later when you need to erase the spaceship. You can simply copy that small portion of background back. However using RAMWRT alone, you couldn't do this.
So what happens if we want to read from both DHR pages?
My linear algebra professor had this understated way of telling the class that he didn't want to explain something because it would require too much time or effort. He would simply say: "It's non-trivial". It didn't take long for us to understand that meant: "Here be Dragons!"
Reading from both DHR pages is...non-trivial. It requires the use of two more softswitches RAMRDOFF ($C002) and RAMRDON ($C003). Using them though, is tricky. Why? Remember when I said that even when RAMWRT is on our program is still being read from MAIN memory? Well as soon as you invoke $C003 - Immediately the 6502 program counter starts reading the next program instruction from AUX memory. If you don't have a program sitting in AUX memory at that location the computer will probably just crash ( more correctly it will execute random bytes as instructions until it encounters a 00 which is a BRK instruction)
FactEarly on, the DHR softswitches must have been rather poorly documented because on page 89 of the manual for Beagle Graphics, a popular set of DHR graphical utilities it actually says that DHR Page 2 "doesn't really exist"
Reading from both DHR pages is...non-trivial. It requires the use of two more softswitches RAMRDOFF ($C002) and RAMRDON ($C003). Using them though, is tricky. Why? Remember when I said that even when RAMWRT is on our program is still being read from MAIN memory? Well as soon as you invoke $C003 - Immediately the 6502 program counter starts reading the next program instruction from AUX memory. If you don't have a program sitting in AUX memory at that location the computer will probably just crash ( more correctly it will execute random bytes as instructions until it encounters a 00 which is a BRK instruction)
To use this feature successfully we need to employ RAMWRT to write a program into the memory location the program counter will be at the instant we invoke RAMRDON. We also need a program sitting in MAIN memory exactly where we expect our program to be when we invoke RAMRDOFF to bring us back into MAIN memory again.
If that sounds like a pain in the ass? You'd be right.
Going forward we will be using both approaches. For doing single pixel plots we will be using 80STOREON as we will need to read screen memory in order to add pixels to the screen without disturbing other bytes. As we start looking at bitmap graphics we will be using 80STOREOFF. Since, at first we will be doing things like character generation. Which can be done by blindly writing to screen memory and later when we start writing arcade games we will do operations like collision detection without reading screen memory at all...
No comments:
Post a Comment