Part I
Mixing Graphics Modes On The 64
Sheldon Leemon
It's possible to have several different graphics modes simultaneously on the 64 screen. Program 1 shows you how to divide the display into three zones: high resolution, regular text, and multicolor bitmap mode. Program 2 uses the same utility program, but creates entirely different effects. The screen displays all three text modes: regular, extended background color, and multicolor.
This graphics technique provides you with significant control over what appears on your screen. For example, you can switch modes with simple POKEs. Although there's plenty of technical information here for advanced programmers, the author has provided instructions and example programs which beginners can follow. Everyone can take advantage of these important techniques.
The Commodore 64 Programmer's Reference Guide hints that more than one graphics mode may be displayed on the screen at once. When it comes time to explain how it can be done, however, the Guide states only that you must set a raster interrupt for the screen line where you want a different type of display to start, set the VIC-II chip for the new mode during that interrupt, and then set up another interrupt to change the mode back a little farther down the display. This explanation might be clear to advanced machine language programmers, but it leaves a lot of others in the dark.
In this tutorial, we'll look at some examples of raster interrupts that can be easily used by BASIC programmers to create split-screen displays and other effects. We'll also discuss, in more detail, how machine language programmers can use the raster interrupt capability.
The Interrupt
The most obvious place to start our discussion is by explaining what an interrupt is. An interrupt is a signal given to the microprocessor (the "brains" of the computer) that tells it to stop executing its machine language program (for example, BASIC itself is a machine language program) and to work on another program for a short time, perhaps only a fraction of a second. After finishing the interrupt program, the computer goes back to executing the main program, just as if there had never been a detour.
There are several ways to cause such an interrupt on the 64. Pressing the RESTORE key causes an interrupt, and if the STOP key is also pressed, the interrupt routine clears the screen and restores the computer to its normal state. There are internal timers on the CIA Input/Output chips that can each generate interrupts. One of these timers is set by the operating system to interrupt every sixtieth of a second, and the interrupt routine that is called is used to check the keyboard and to update the jiffy clock which is used by TI and TI$. In addition, the VIC-II chip can also interrupt normal program execution when one of a number of events related to the graphics display occurs. One of these is called a raster interrupt.
On a normal TV display, a beam of electrons (raster) scans the screen, starting in the top left-hand corner and moving in a straight line to the right, lighting up appropriate parts of the screen line on the way. When it comes to the right edge, the beam moves down a line and starts again from the left. There are 263 such lines that are scanned by the 64 display, 200 of which form the visible screen area. This scan updates the complete screen display 60 times every second.
The VIC-II chip has memory registers that keep track of the line that the raster is scanning at any given moment. Since the line number can be greater than 255, one register is not enough to do the job. Therefore, the part of the number that is less than 256 is kept in location 53266 ($D012 hex), and if bit 7 of location 53265 ($D011) is set to 1, 256 is added to that number to arrive at the correct scan line. Of course, since these numbers change 15,780 times per second, a BASIC program executes far too slowly to read the registers and take effective action based on their contents. Only a machine language program has the speed to accomplish something with a particular raster scan line, and even it may not be quick enough to change the display without some slight, but visible, disruption.
The raster registers have two functions. When read, they tell what line is presently being scanned. But when written to, they designate a particular scan line as the place where a raster interrupt will occur. If the raster interrupt is enabled, the interrupt program will be executed at the exact moment that the raster beam reaches that line. This allows the user to reset any of the VIC-II registers at any point in the display and thus change character sets, background color, or graphics mode for only a part of the screen display.
Setting up a raster interrupt program is admittedly not a job for a beginning programmer, but with the following step-by-step explanation, most machine language programmers should be able to write such a routine. Those with no machine language experience should read the explanation in order to get a general idea of what is taking place. Afterwards, we'll see how to use the example interrupt routine even if you don't know anything about machine language programming.
Writing A Raster Interrupt
When you have finished writing the machine language routine that you want the interrupt to execute, the steps required to set up the raster Interrupt are:
- Set the interrupt disable flag in the status register with an SEI instruction. This will disable all interrupts and prevent the system from crashing while you are changing the interrupt vectors.
- Enable the raster interrupt. This is done by setting bit 0 of the VIC-II chip interrupt enable register at location 53274 ($D01A) to 1.
- Indicate the scan line on which you want the interrupt to occur by writing to the raster registers. Don't forget that this is a 9-bit value, and you must set both the low byte (in location 53264) and the high bit (in the register at 53265) in order to insure that the interrupt will start at the scan line you want it to, and not 256 lines earlier or later.
- Let the computer know where the machine language routine that you want the interrupt to execute starts. This is done by placing the address in the interrupt vector at locations 788–789 ($314–$315). This address is split into two parts, a low byte and a high byte, with the low byte stored at 788. To calculate the two values for a given address AD, you may use the formula HIBYTE = INT(AD/256) and LOWBYTE = AD-(HIBYTE*256). The value LOWBYTE would go into location 788, and the value HIBYTE would go into location 789.
- Re-enable interrupts with a CLI instruction, which clears the interrupt disable flag on the status register.
When the computer is first turned on, the interrupt vector is set to point to the normal hardware timer interrupt routine, the one that advances the jiffy clock and reads the keyboard. Since this interrupt routine uses the same vector as the raster interrupt routine, it is best to turn off the hardware timer interrupt by putting a value of 127 in location 56333. If you want the keyboard and jiffy clock to function normally while your interrupt is enabled, you must preserve the contents of locations 788 and 789 before you change them to point to your new routine. Then you must have your interrupt routine jump to the old interrupt routine exactly once per screen refresh (every sixtieth of a second).
Another thing that you should keep in mind is that at least two raster interrupts are required if you want to change only a part of the screen. The interrupt routine must not only change the display, but it must also set up another raster interrupt that will change it back.
Program 1 is a BASIC program that uses a raster-scan interrupt to divide the display into three sections. The first 80 scan lines are in high-resolution bitmap mode, the next 40 are regular text, and the last 80 are in multicolor bitmap mode. The screen will split this way as soon as a SYS to the routine that turns on the interrupt occurs, and the display will stay split even after the program ends. Only if you hit the STOP and RESTORE keys together will the display return to normal.
Program 2 shows how a completely different split screen can be set up using the same machine language program. The DATA statements for the interrupt routine are the same as for Program 1, except for the tables starting at line 49264. By changing these tables, we now have a display that shows all three text modes: regular, extended background color, and multicolor. Upper– and lowercase text are mixed, and each area has a different background color. This program also shows that you can change the table values during a program by POKEing the new value into the memory location where those table values are stored. In that way, you can, for example, change the background color of any of the screen parts while the program is running.
Once you know how to use all the graphics features that the VIC-II chip makes available, the sample interrupt program should enable you to combine several different display modes on a single screen, so that you can take maximum advantage of the 64's graphics power.
Program 1: Text With Graphics
10 FOR I = 49152 TO 49278 : READ A:POKE I,A : NEXT : sys12 * 4096 20 PRINT CHR$ (147) : FOR I = 0 TO 8 : PRINT : NEXT 30 PRINT "THE TOP AREA IS HIGH-RES BIT MAP MODE" 40 PRINT : PRINT "THE MIDDLE AREA IS ORDINARY TEXT" 50 PRINT: PRINT "THE BOTTOM AREA IS MULTICOLOR BIT MAP" 60 FORG = 1024 TO 1383 : POKEG, 114 : NEXT : FORG = 1384 TO 1423 : POKE, G, 6 : NEXT 70 FORG = 1664 TO 2023 : POKEG, 234 : NEXT 80 FORG = 55936TO56295 : POKEG, 13 : NEXT 90 FOR I = 8192 TO 11391 : POKE I, 0 : POKE I + 4800, 0: NEXT 100 BASE = 2 * 4096 : BK = 49267 110 H = 40 : C = 0 : FORX = 0TO319 : GOSUB150 : NEXT 120 H = 160 : C = 0 : FORX = 0TO319STEP2 : GOSUB150 : NEXT:C = 40 : FORX = 1TO319STEP2 : GOSUB150 : NEXT 130 C = 80 : FOR X = 0 TO 319 STEP2 : W = 0 : GOSUB150 : W = 1 : GOSUB150:NEXT 140 GOTO 140 150 Y = INT (H + 20 * SIN(X/10 + C)) : CH = INT(X/8) : RO = INT (Y/8) : LN = YAND7 160 BY = BASE + RO * 320 + 8 * CH + LN : BI = ABS(7-(XAN D7) - W) 170 POKEBY,PEEK(BY)OR(2 ↑ BI) :RETURN 49152 DATA 120, 169, 127, 141, 13, 220 49158 DATA 169, 1, 141, 26, 208, 169 49164 DATA 3, 133, 251, 173, 112, 192 49170 DATA 141, 18, 208, 169, 24, 141 49176 DATA 17, 208, 173, 20, 3, 141 49182 DATA 110, 192, 173, 21, 3, 141 49188 DATA 111, 192, 169, 50, 141, 20 49194 DATA 3, 169, 192, 141, 21, 3 49200 DATA 88, 96, 173, 25, 208, 141 49206 DATA 25, 208, 41, 1, 240, 43 49212 DATA 198, 251, 16, 4, 169, 2 49218 DATA 133, 251, 166, 251, 189, 115 49224 DATA 192, 141, 33, 208, 189, 118 49230 DATA 192, 141, 17, 208, 189, 121 49236 DATA 192, 141, 22, 208, 189, 124 49242 DATA 192, 141, 24, 208, 189, 112 49248 DATA 192, 141, 18, 208, 138, 240 49254 DATA 6, 104, 168, 104, 170, 104 49260 DATA 64, 76, 49, 234 49264 DATA 49, 170, 129 : REM SCAN LINES 49267 DATA 0, 6, 0 : REM BACKGROUND COLOR 49270 DATA 59, 27, 59 : REM CONTROL REG. 1 49273 DATA 24, 8, 8:REM CONTROL REG. 2 49276 DATA 24, 20, 24 : REM MEMORY CONTROL
Program 2: The Three Text Modes
10 FOR I = 49152 TO 49278 : READ A : POKE I, A : NEXT : SYS12 * 4096 20 PRINTCHR$(147)CHR$ (5) : POKE 53280, 0 30 POKE 53280, 0 : POKE 53282, 6 : POKE 53283, 5 : POKE 53284, 4 40 PRINT : PRINT"THIS IS MULTI-COLOR TEXT MODE" 50 PRINT : PRINT"FOUR-COLOR CHARACTERS ARE HARD TO READ" 60 PRINT : PRINT CHR$(150) "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 70 PRINT : PRINT : PRINT : PRINT CHR$(28) "THIS IS NORMAL TEXT MODE ..." 80 PRINT : PRINT "NOTHING FANCT GOING ON HERE" : PRINT : PRINT : PRINT 90 PRINTCHR$(144) "{6 SPACES} EX{RVS}TE{OFF}ND {RVS}ED{OFF} BA{RVS}CK{OFF}GR{RVS}OU {OFF}ND{RVS} C{OFF}OL{RVS}OR{OFF} MO{RVS}DE{OFF}UP" 100 PRINT : PRINT "LETS YOU USE DIFFERENT BACKGROUND COLORS" 110 PRINT "{RVS}LETS YOU USE DIFFERENT BACKGROUND COLORS" 120 PRINT "LETS{SHIFT-SPACE}YOU{SHIFT-SPACE}USE {SHIFT-SPACE}DIFFERENT{SHIFT-SPACE}BACKGROUND{SHIFT-SPACE}COLORS" 130 PRINT "{RVS}LETS{SHIFT-SPACE}YOU{SHIFT-SPACE}USE {SHIFT-SPACE}DIFFERENT{SHIFT-SPACE}BACKGROUND{SHIFT-SPACE}COLORS"; 140 FORS = 0TO3000 : NEXT 150 FORS = 49267TO49269 : POKES, RND (1) * 16 : FOR I = 1 TO 2000 : NEXT I, S : GOTO 140 49152 DATA 120, 169, 127, 141, 13, 220 49158 DATA 169, 1, 141, 26, 208, 169 49164 DATA 3, 133, 251, 173, 112, 192 49170 DATA 141, 18, 208, 169, 24, 141 49176 DATA 17, 208, 173, 20, 3, 141 49182 DATA 110, 192, 173, 21, 3, 141 49188 DATA 111, 192, 169, 50, 141, 20 49194 DATA 3, 169, 192, 141, 21, 3 49200 DATA 88, 96, 173, 25, 208, 141 49206 DATA 25, 208, 41, 1, 240, 43 49212 DATA 198, 251, 16, 4, 169, 2 49218 DATA 133, 251, 166, 251, 189, 115 49224 DATA 192, 141, 33, 208, 189, 118 49230 DATA 192, 141, 17, 208, 189, 121 49236 DATA 192, 141, 22, 208, 189, 124 49242 DATA 192, 141, 24, 208, 189, 112 49248 DATA 192, 141, 18, 208, 138, 240 49254 DATA 6, 104, 168, 104, 170, 104 49260 DATA 64, 76, 49, 234 49264 DATA 49, 177, 113 :REM SCAN LINES 49267 DATA 2, 7, 6:REM BACKGROUND COLOR 49270 DATA 91, 27, 27 :REM CONTROL REG. 1 49273 DATA 8, 8, 24 : REM CONTROL REG. 2 49276 DATA 20, 22, 20 : REM MEMORY CONTROL