Advanced Commodore 128 Video
Jim Butterfield, Associate Editor
Here's how to relocate screen memory and set up a custom character set on the Commodore 128—two valuable techniques worth mastering on any computer. When you run the example program, be ready for a surprise. For intermediate and advanced BASIC programmers.
You can do a lot of graphics on the Commodore 128 with an elementary knowledge of the new BASIC: circles, squares, lines, and points appear by means of simple BASIC commands. But advanced programmers may still need to get into the mechanics of video. Here's a simple exercise for 128-mode 40-column screens that will give a little insight into the "works."
The question often arises: How can I implement a new character set? Some people want to design their own personalized codes or graphics symbols for the screen; others are interested in foreign languages. In 40 columns, the 8564 video chip is practically identical to the 6567 of the Commodore 64. With a few new rules, we can put the chip's features to work in the same way.
Because the Commodore 128 makes it easy, I'll be including some hexadecimal addresses in the following listing. If you'd rather use decimal numbers, the computer will do quick conversions for you, and you can make the substitutions in the program.
Changing Addresses
Let's build the program step by step and note points of interest.
100 POKE 58, DEC ("C0") 110 CLR
I'm planning to put the screen and its new character set into memory bank 1, at addresses $C000 to $CBFF—character set at $C000, screen at $C800. (By the way, if you'd rather use the decimal value 192 instead of DEC("C0"), be my guest. I prefer C0 because it's easier to visualize it as part of the full address $C000. Be sure to type a zero and not the letter o or you'll get an error.) Bank 1 is where BASIC puts its variables; we wouldn't want these to get mixed up with our screen. So we cut down the top-of-variable-memory pointer to $C000. There's really no danger of a memory conflict with this small program, but we might as well do it right.
The CLR command makes sure the other variable pointers don't get mixed up by this change.
120 TRAP 500
This command may be unfamiliar to many Commodore programmers. It sets up an error trap so that if anything goes wrong in the following code, the computer hops to line 500, which will restore the screen. This saves us from the horrible prospect of watching the program stop with a syntax error while the screen is still scrambled and unreadable. The TRAP command gives us another bonus: If the computer freezes—or is just too slow—we can press STOP, and the program zips to line 500 and wraps things up.
130 BANK 15
We're about to fiddle with the insides of computer chips (registers), so this command calls for memory bank 15 to make the chips accessible. This assures that the next few POKEs will be directed to the right place.
140 POKE DEC ("DD00"), 148
Except for the decimal number conversion ($DD00 = 56576), this POKE is identical to the way it's done on the Commodore 64. Briefly, it means: Display video out of the memory slice in the range $C000 to $FFFF. We haven't specified the bank yet, but we'll get around to it in a moment.
150 POKE DEC ("0A2C"), 32
We're still in bank 15, but this address isn't a chip. The address $0A2C (decimal 2604) is below $4000 (16384). When we're using bank 15, all such low addresses go to RAM, bank 0. This POKE sets the position of the character set and the screen within the video slice we've selected. The calculation goes like this: We want the screen to be at $C800, which is 2K above the start of the video slice at $C000, so multiply the 2 by 16 and add a similar value for the character set. In this case, the character set is right at the start of the slice; so we add 0 to get a value of 32.
On the Commodore 64, we'd do exactly the same calculation, but we'd put the result in address $D018 (53272). In fact, that's the same address at which our value will end up in the Commodore 128, but we must let the computer's interrupt routine deliver it there for us. So instead of POKEing the value directly into $D018, we store it at $0A2C (2604). As part of the computer's interrupt procedure, it will copy the contents of this location into $D018.
160 POKE DEC ("D506"), 68
This tells the computer to take video from bank 1. If we wanted video from bank 0, we'd POKE a value of 4—or just leave this line out, since that's the value that will be there in any case.
170 POKE 217, 4
This POKE tells the computer to take its video from RAM, not ROM. We don't need to give this one for the addresses we have chosen, since there is no conflict. This very low address has a special banking rule: All addresses below hex $400 (1024) go to RAM bank 0, regardless of the bank which has been specified.
Relocating The Screen
Now our video is set up and ready to go. We'd better put something on the screen so we can see it working. It seems sensible to copy our old screen to the new place; then we'll copy the character set. We'll make a slight change so you can see how to create a new set of characters.
First, our screen must move from bank 0, address $400, to bank 1, address $C800. We must move the whole thousand characters.
200 FOR J = 0 TO 999 210 BANK 0 : X = PEEK (1024 + J) 220 BANK 1 : POKE DEC("C800") + J, X 230 NEXT J
This moves screen memory, but since the character set is not in place, the result would look rather muddy. We can read the character set by selecting bank 14; it is found in this bank at addresses $D000 to $D7FF. There are 256 characters times 8 bytes per character, which means 2,048 bytes to move. Just as we moved the screen in the lines above, we must move the character bytes one at a time, flipping between banks 14 and 1.
We'll also change the characters slightly as we move them. This allows us to see that indeed we've taken control of the character set.
300 FOR J = DEC ("C000") TO DEC ("C7FF") STEP 8 310 FOR K = 0 TO 7 320 BANK 14 330 X = PEEK (J + 4096 + 7 - K) 340 BANK 1 350 POKE J + K, X 360 NEXT K 370 NEXT J
This puts the character set in place. When you run the program (after typing in the additional lines below), you should see your original computer screen—slightly changed. We could insert a delay loop to prolong the effect, but the screen takes long enough to change that you'll have plenty of time to see what happens.
Cleaning Up
We're finished—almost. We must be neat and put everything back the way it was. This also gives you a chance to see the original values that were in the various registers and addresses.
500 BANK 15 510 POKE DEC ("DD00"), 151 520 POKE DEC ("0A2C"), 20 530 POKE DEC ("D506"), 4 540 POKE 217, 0
These lines restore the original screen. A little study should enable you to guess at what each POKE does—or undoes.
Finally, we need two last lines to complete the job. But there's an important note: Do not enter these lines until you've tested the program and found it good. If your program has a problem, you'll want to be able to look at the variables (by using commands such as PRINT J) to find out what went wrong. These final lines make it impossible for you to do so.
550 POKE 58, DEC ("FF") 560 CLR
We've given back to the computer its variable storage memory. And the job is complete.