by Rick Kephart 5/21/88 This shows how to take whatever is in the memory area 8192-16191 (the normal HIRES screen on the 128), such as a DOODLE picture (which can be loaded with LOAD "DDfilename",B0,p7168), or a picture made by 128-BASIC, and put it up on the RGB screen. The first part of this file shows to do it with a C-128 with only 16K video memory (unenhanced). The picture will be in black-and-white. The second part of this file shows how to do the same thing with 64K video memory (as in a C-128D), to produce a color picture. To run the program, simply BLOAD"HIRES80",B15,P4864, make sure something is in the HIRES bitmap at 8192, switch to 80-columns, and type SYS4864, or whatever start address you load the program in at (it is completely relocatable: you can BLOAD"HIRES80",B15,P5000, the SYS5000, or use any available starting address, but you Must remain in Bank 15!). Then you can switch back to the Text screen simply by pressing the RUN/STOP key. This was written using only the 128's built-in ML monitor. I will explain each step. The first thing we will want to do is switch to FAST mode. This is a simple process. (This is actually simply BASIC's FAST routine). First we set Bit 4 in the Control Register at 53265 (HEX=$D011) to 0, by reading the value there with LDA and then ANDing the value there with Binary 11101111 (HEX=$6F), which turns off Bit 4 but does not affect anything else. This is the Bit which blanks the 40-column screen. 1300 AD 11 D0 LDA $D011 1303 29 6F AND #$6F 1305 8D 11 D0 STA $D011 Then we go to the Clock Rate Register at 53296 (HEX=$D030) and turn on Bit 0. This changes the Clock Rate from 1 MHz (SLOW) to 2 MHz (FAST). The other bits are unimportant and need not be retained, so we can simply put a 1 in that register. 1308 A9 01 LDA #$01 130A 8D 30 D0 STA $D030 The next step is to set up the 8563 to Bitmap display. This is controlled by Register #25 (HEX=$19). The Register will also turn off Attribute memory, which we must also do. Attribute memory controls individual character colors, as well as Reverse and Blink. Since we will not have any room available for any attributes, they must be turned off. To read or write to the 8563, we use the doorway at memory locations 54784 and 54785 (HEX=$D600 and $D601). It is only at these two memory locations that we can communicate with the 8563 Video Chip. This is done by storing the Register we want to read or write to $D600, then waiting for Bit 7 at $D600 to be set to 1 (BPL will branch while Bit 7 is off), indicating that $D601 is ready for action. As soon as that happens, we go to work on $D601, reading or writing our value. Register $19 will contain a different value depending on the particular 8563 chip in the particular 128 being used (there are two versions). Therefore, we cannot simply put a value there with Attributes-Off and Bitmap-On. Instead, we must first read the value that is there. 130D A2 19 LDX #$19 130F 8E 00 D6 STX $D600 1312 2C 00 D6 BIT $D600 1315 10 FB BPL $1312 1317 AD 01 D6 LDA $D601 Then we will put this normal value for Register $19 away. Let's use location $16, a Zero-page location normally used by BASIC, but available to us now since we're not using BASIC. 131A 85 16 STA $16 Now we must turn off Attributes and turn on Bitmap. Bits 6 and 7 of the register control these two 8563 things. To turn on the Bitmap, we must set Bit 7 to 1. We'll do this by ORing it with Binary 10000000 (HEX=$80) to turn on Bit 7 without affecting any other bit. To turn off the Attributes, we've got to get Bit 6 to 0. Let's do that by ANDing it with Binary 10111111 (HEX=$BF), which will turn Bit 6 off without affecting any other bit. 131C 09 80 ORA #$80 131E 29 BF AND #$BF Now we will use BASIC's built-in routine to write a vaue to a register, which is at 52684 (HEX=$CDCC). To do this, the register must be in the X-register, and the value to write must be in the Accumulator. The routine writes the register in X to $D600, waits for Bit 7 of $D600 to be on, then writes the value in the Accumulator to $D601. (The X-register still contains $19.) 1320 20 CC CD JSR $CDCC The next thing we must do is set up the 8563 to start reading data, and storing it at location $0000 in the 8563's RAM memory. We have to start at $0000 because we need every byte from $0000 to the highest location, $3FFF. The Screen Memory's location, which is controlled by Registers 12 and 13 (HEX=$0C and $0D) are already set to 0 to start the screen at $0000, so we don't have to worry about them. But we do need to set the Current Memory Address registers 18 and 19 (HEX=$12 and $13) to $0000, so when we start writing to the 8563's RAM, the data will start at $0000. Once these have been set for the address at which we want to start writing, it is updated automatically for each byte we write (nice of it to do that for us, isn't it?). (Unlike all other addresses with the 6502 or 6510 or 8510 microprocessors, addresses in the 8563 are written high-byte First, then low-byte, the opposite order. In this case, though, since the high- and low-bytes of the address are the same, this peculiarity is not visible here.) To do this, we will again use our built-in write-to-the- 8563-chip routine at $CDCC. We will set the Accumulator to 0 and the X-register to $12. Then we will simply use INX to increase the X-register to write the low-byte to $13. 1323 A9 00 LDA #$00 1325 A2 12 LDX #$12 1327 20 CC CD JSR $CDCC 132A E8 INX 132B 20 CC CD JSR $CDCC The next byte in the program is just an NOP, separating the preliminaries from the actual main routine to write the one memory into the other. 132E EA NOP Now the real work begins! The hardest part of this project is reading the VIC HIRES screen, because the VIC stores Bitmap memory in vertical blocks of 8 bytes in horizontal rows of 40 blocks across, whereas the 8563 uses 80 sequential bytes across each row. What we must do is read bytes from the VIC Bitmap in horizontal rows, and not sequentially. Here is a BASIC way to do this: FOR A = 8192 TO 16191 STEP 320: FOR B = 0 TO 7: FOR C = 0 TO 312 STEP 40: X = PEEK(A+B+C): NEXT C,B,A That's what we have to do in Machine Language! Not an easy task. It is worth it, though, Because this BASIC routine is very slow. I decided to convert this exact routine into machine language. Here's how I did it: I picked a couple of BASIC's Zero-page locations for a counter for 8192 to 16191. I chose locations $10 and $11, and stored 8192 (HEX=$2000) there to begin. 132F A9 20 LDA #$20 1331 85 11 STA $11 1333 A9 00 LDA #$00 1335 85 10 STA $10 Here is where the biggest loop begins! We're going to copy the address stored in $10 & $11 to a couple more of BASIC's Zero-page locations (I'm sure BASIC won't mind), $12 and $13. This way, we can update the address in groups of 8 until we get to the end of a 40-byte row, and then update the address by 320 to go on to the next row. 1337 A5 10 LDA $10 1339 85 12 STA $12 133B A5 11 LDA $11 133D 85 13 STA $13 I'm going to use another Zero-page location, $14, to count from 0 to 7. This will be used as a Y-index. We have to have a memory location to store it, because we'll be needing the Y-register later on. 133F A9 00 LDA #$00 1341 85 14 STA $14 One more of BASIC's Zero-page locations, $15, we'll use to count from 1 to 40, to tell us when we've reached the end of a HIRES row. But let's use it as a countdown, starting by putting 40 (HEX=$28) and wait 'till we reach zero. 1343 A9 28 LDA #$28 1345 85 15 STA $15 Now let's get started, at last! We'll put the value in $14 (something between 0-7) into the Y-register, and read a byte from the VIC HIRES screen at 8192-16191. 1347 A4 14 LDY $14 1349 B1 12 LDA ($12),Y Now comes the really interesting part. Since the 8563 Bitmap display is 640X199 bits and the VIC Bitmap is only 320X199 bits, every bit of the VIC display must be doubled to fill the entire 8563 Bitmap. This is one of those rare cases of numerical manipulations which are actually much easier to do in Machine Language than in BASIC! What will happen is each byte will be doubled into two byte, one with each of the first 4 bits doubled, and the other with the other 4 bits of the original number doubled (8 bits doubled = 16 bits, or 2 bytes). The first thing we'll do is set up the X-register as a counter for the high 4 bits and then the low 4 bits of each byte (that is, we must run through this routine twice: once for each set of 4 bits). This will also serve as a Zero-page Index! 134B A2 01 LDX #$01 Now, we'll copy the byte into two Zero-page locations. Let's give BASIC a break and use $FD and $FE. 134D 85 FD STA $FD 134F 85 FE STA $FE Now we'll put a 4 in the Y-register to count down the 4 bits to double at a time. 1351 A0 04 LDY #$04 Now is the time to start doubling! We'll use the ML instruction ROL. The Carry will hold whether the bit is 0 or 1. We don't have to worry about CLC or ASL, because we'll be using all 8 bits, and it won't matter what ends up in $FD and $FE when we're done! As each bit is rolled out into the carry, we'll roll it into a Zero-page location. The 2 bytes which will hold the final two bytes will be $FB and $FC, pointed to by the X-register! We have the byte in two memory locations, so it will be a simple matter to double the bit simply by rolling each bit out twice. 1353 26 FD ROL $FD 1355 36 FB ROL $FB,X 1357 26 FE ROL $FE 1359 36 FB ROL $FB,X 135B 88 DEY 135C D0 F5 BNE $1353 Now the top four bits of $FD and $FE contain what used to be the low 4 bits. It makes no difference what's now in the 4 low bits of $FD and $FE, we'll never see them. 135E CA DEX 135F F0 F0 BEQ $1351 Now $FC and $FB contain the value from the VIC screen with each bit doubled. So now we're ready to write two bytes to the 8563 Bitmap. The Memory read/write gateway to the 8563 is Register 31 (HEX=$1F). Again, we'll use the routine at $CDCC to write the two bytes to the 8563 RAM memory, and thereby put them up on the Bitmap display. 1361 A2 1F LDX #$1F 1363 A5 FC LDA $FC 1365 20 CC CD JSR $CDCC 1368 A5 FB LDA $FB 136A 20 CC CD JSR $CDCC Time now to go to the next horizontal byte of the VIC Bitmap. This byte is 8 away from the previous byte. We'll do this with a simple addition routine, adding 8 to the base address in $12 & $13. 136D 18 CLC 136E A9 08 LDA #$08 1370 65 12 ADC $12 1372 85 12 STA $12 1374 A9 00 LDA #$00 1376 65 13 ADC $13 1378 85 13 STA $13 Now we'll use our countdown counter we've set up in $15 to see if we've reached the end of a row yet, and look back if we haven't. 137A C6 15 DEC $15 137C D0 C9 BNE $1347 Now we've got one line of bytes. We have 8 more lines of 40 bytes each to get. Remember, we use location $14 to store our Y-index offset. Each byte of each row will be 1 byte higher than the previous row. First, we're getting the first byte of each 8-byte block, so we have one horizontal row. The next horizontal row will consist of the second byte of each 8-byte block. The third row will be the third byte of each block, and so on until we've reached all 8 bytes. As we go to each byte of the block, we must maintain the base address as the first byte of the first block, so our offset will point to the right byte. 137E E6 14 INC $14 1380 A5 10 LDA $10 1382 85 12 STA $12 1384 A5 11 LDA $11 1386 85 13 STA $13 Now we check to see if we've finished the 8-byte block. 1388 A5 14 LDA $14 138A C9 08 CMP #$08 138C D0 B5 BNE $1343 Now the time has come to jump to the next row of 8-byte blocks. We do this by adding 320 (HEX=$0140) to the base address. This is a simple addition routine. 138E 18 CLC 138F A9 40 LDA #$40 1391 65 10 ADC $10 1393 85 10 STA $10 1395 A9 01 LDA #$01 1397 65 11 ADC $11 1399 85 11 STA $11 Now we check to see if we're finished. We'll be finished when we have worked our way up to location 16191 (HEX=$3F3F). We already have the high byte in the accumulator, so we'll check and see if that's $3F yet. If it is, then we'll check to see if the low byte is higher than $3F. 139B C9 3F CMP #$3F 139D D0 98 BNE $1337 139F A5 10 LDA $10 13A1 C9 3F CMP #$3F 13A3 90 92 BCC $1337 Hurrah! The VIC Bitmap is now on display on the 8563 RGB screen! Now we'll keep this on the screen, until the STOP key has been pressed. Location 145 (HEX=$91) is constantly updated by the Kernal to contain the value of the column of the Keyboard scan which has the STOP key. Bit 7 is cleared to 0 whenever the STOP key is pressed. BMI loops as long as Bit 7 is 1, so it will loop until the STOP key is being pressed. 13A5 A5 91 LDA $91 13A7 30 FC BMI $13A5 The Bitmap is nice to look at, but eventually we'll want to be able to see characters on the screen again! Remember when we stored the original value of Register $19 in location $16? Well, here's where we finally use it! This will turn the Bitmap off and turn the Attributes back on again. 13A9 A2 19 LDX #$19 13AB A5 16 LDA $16 13AD 20 CC CD JSR $CDCC But we've still got us a problem here! Since we used the entire 16K to display our Bitmap, we have overwritten the entire 8563 character-set. We know have the text screen set up, but no character data to be able to print characters to print to it! The Kernal will come to our rescue here. When the 8563 is first initialized, VIC's character set is copied into the 8563 RAM, in the character memory storage area (which, by the way, is located at 8192 to 16383 (HEX=$2000 to $3FFF) in the 8563's RAM memory). The 128 Kernal's Jump Table has a entry called INIT80, which carries out this copying procedure, at 65378 (HEX=$FF62). It jumps to the actual routine which is in in the Screen Editor ROM at 49191 (HEX=$C027). 13B0 20 62 FF JSR $FF62 Now the Text screen is being displayed by the 8563, and we have all our characters in memory so we can display them. But there's still one thing wrong. Attribute memory is turned on, but is filled with strange data, whatever was in the Bitmap display from 2048 to 4096 (HEX=$0800 to $1000) which is where the 8563 stores the Attributes in its memory. That's why you see that bizarre display for an instant after the Bitmap is switched out. Attribute memory is easiest to clear by simply clearing the screen, by printing the CLR/HOME character of CHR$(147) (HEX=$93) through the Kernal output routine at $FFD2. 13B3 A9 93 LDA #$93 13B5 20 D2 FF JSR $FFD2 And now we're finished! Back to BASIC. Bye bye! 13B8 60 RTS Switch to FAST mode 1300 AD 11 D0 LDA $D011 1303 29 6F AND #$6F 1305 8D 11 D0 STA $D011 1308 A9 01 LDA #$01 130A 8D 30 D0 STA $D030 Now we set up the VDC for BITMAP display, but do NOT turn off attributes! 130D A2 19 LDX #$19 130F 8E 00 D6 STX $D600 1312 2C 00 D6 BIT $D600 1315 10 FB BPL $1312 1317 AD 01 D6 LDA $D601 131A 85 16 STA $16 131C 09 80 ORA #$80 131E 20 CC CD JSR $CDCC Now, change the screen memory from $0000-$4000 up to $8000€$C000. The screen memory is determined by the values in registers 12 and 13 ($0C & $0D) in high-byte/low-byte format: 1321 A9 80 LDA #$80 1323 A2 0C LDX #$0C 1325 20 CC CD JSR $CDCC 1328 E8 INX 1329 A9 00 LDA #$00 132B 20 CC CD JSR $CDCC Now we set the current write-address to $8000 by putting that value into registers 18 & 19: 132E A9 80 LDA #$80 1330 A2 12 LDX #$12 1332 20 CC CD JSR $CDCC 1335 A9 00 LDA #$00 1337 E8 INX 1338 20 CC CD JSR $CDCC No we convert the VIC bitmap to the VDC bitmap, just like in the 128 version 133B A9 20 LDA #$20 133D 85 11 STA $11 133F A9 00 LDA #$00 1341 85 10 STA $10 1343 A5 10 LDA $10 1345 85 12 STA $12 1347 A5 11 LDA $11 1349 85 13 STA $13 134B A9 00 LDA #$00 134D 85 14 STA $14 134F A9 28 LDA #$28 1351 85 15 STA $15 1353 A4 14 LDY $14 1355 B1 12 LDA ($12),Y 1357 A2 01 LDX #$01 1359 85 FD STA $FD 135B 85 FE STA $FE 135D A0 04 LDY #$04 135F 26 FD ROL $FD 1361 36 FB ROL $FB,X 1363 26 FE ROL $FE 1365 36 FB ROL $FB,X 1367 88 DEY 1368 D0 F5 BNE $135F 136A CA DEX 136B F0 F0 BEQ $135D 136D A2 1F LDX #$1F 136F A5 FC LDA $FC 1371 20 CC CD JSR $CDCC 1374 A5 FB LDA $FB 1376 20 CC CD JSR $CDCC 1379 18 CLC 137A A9 08 LDA #$08 137C 65 12 ADC $12 137E 85 12 STA $12 1380 A9 00 LDA #$00 1382 65 13 ADC $13 1384 85 13 STA $13 1386 C6 15 DEC $15 1388 D0 C9 BNE $1353 138A E6 14 INC $14 138C A5 10 LDA $10 138E 85 12 STA $12 1390 A5 11 LDA $11 1392 85 13 STA $13 1394 A5 14 LDA $14 1396 C9 08 CMP #$08 1398 D0 B5 BNE $134F 139A 18 CLC 139B A9 40 LDA #$40 139D 65 10 ADC $10 139F 85 10 STA $10 13A1 A9 01 LDA #$01 13A3 65 11 ADC $11 13A5 85 11 STA $11 13A7 C9 3F CMP #$3F 13A9 D0 98 BNE $1343 13AB A5 10 LDA $10 13AD C9 3F CMP #$3F 13AF 90 92 BCC $1343 Now here is where the color is added. First we move Attribute memory from its normal location at $0800 up to the unused area at $1000. This move is done so that the old attributes will be preserved when we switch back to the text display. The location of Attribute memory is determined by the values in registers 20 & 21 ($14 & $15) 13B1 A9 10 LDA #$10 13B3 A2 14 LDX #$14 13B5 20 CC CD JSR $CDCC 13B8 A9 00 LDA #$00 13BA E8 INX 13BB 20 CC CD JSR $CDCC Reset the current write to memory location 13BE A9 10 LDA #$10 13C0 A2 12 LDX #$1213C2 20 CC CD JSR $CDCC 13C5 A9 00 LDA #$00 13C7 E8 INX 13C8 20 CC CD JSR $CDCC 40-column color memory is stored starting at location $1C00 (7168). Let's use a dynamic routine to read the colors, by storing the address within the program 13CB A9 1C LDA #$1C 13CD 8D D7 13 STA $13D7 13D0 A9 00 LDA #$00 13D2 8D D6 13 STA $13D6 Now we get the value, then convert it to 2 4-bit nibbles 13D5 AD 00 1C LDA $1C00 13D8 48 PHA 13D9 4A LSR 13DA 4A LSR 13DB 4A LSR 13DC 4A LSR 13DD A8 TAY There is a table of color translation between 40-column and 80-column stored in ROM starting at $CEC5. We'll put each nibble in the Y-register to use as an offset to get the equivalent 80-column color 13DE B9 5C CE LDA $CE5C,Y 13E1 85 FE STA $FE 13E3 68 PLA 13E4 29 0F AND #$0F 13E6 A8 TAY 13E7 B9 5C CE LDA $CE5C,Y The two halves of the byte (foreground and background colors) are combined 13EA 0A ASL 13EB 0A ASL 13EC 0A ASL 13ED 0A ASL 13EE 05 FE ORA $FE 13F0 A2 1F LDX #$1F Each color must be stored in the 80-column bitmap twice, since the entire display is expanded twice as wide 13F2 20 CC CD JSR $CDCC 13F5 20 CC CD JSR $CDCC Loop back if not done (at $2000) 13F8 EE D6 13 INC $13D6 13FB D0 D8 BNE $13D5 13FD EE D7 13 INC $13D7 1400 AD D7 13 LDA $13D7 1403 C9 20 CMP #$20 1405 D0 CE BNE $13D5 Check for STOP key 1407 A5 91 LDA $91 1409 30 FC BMI $1407 Turn off bitmap and restore test screen 140B A5 16 LDA $16 140D A2 19 LDX #$19 140F 20 CC CD JSR $CDCC Put Attribute memory back at $0800 1412 A9 08 LDA #$08 1414 A2 14 LDX #$14 1416 20 CC CD JSR $CDCC 1419 E8 INX 141A A9 00 LDA #$00 141C 20 CC CD JSR $CDCC Put screen memory back at $0000 141F A9 00 LDA #$00 1421 A2 0C LDX #$0C 1423 20 CC CD JSR $CDCC 1426 E8 INX 1427 20 CC CD JSR $CDCC 142A 60 RTS And return End of file.
You can write to me at .
HOME | Religion | Latin Mass | Denton | Prayer Requests | Homeschooling |
Stories | Art | ******* | Commodore | Miniatures | |
England | Italy | Florida | Musical | Gregorian Chant | LPH Resource Center |