Visiting The VIC-20 Video
Jim Butterfield, Associate Editor
This month our traveller stakes a claim — but discovers he must first find empty land, and must subsequently register his address.
We know that the VIC-20 video chip gets two things from memory: "screen memory" and "the character set." But it sees the computer's memory in an unusual way:
How the video chip sees memory.
Suppose we want to lay out our own screen and characters. It seems simple enough: choose the locations for screen memory and character set, and POKE the block numbers (screen block times 16 plus character block) into address 36869. If the screen is positioned at an exact block boundary, we put a low number (such as 22) into 36866, otherwise we place a high number there (such as 22 plus 128, or 150). The 22, by the way, is for 22 columns — standard for the VIC.
However, we have two major tasks to perform. First, we must make sure that the memory we are using to feed the video chip isn't needed by somebody else. Second, we must tell the VIC-20 operating system about our new screen location. Changing the video chip isn't enough — the parts of the computer that print to the screen must be told that the screen is somewhere else.
Let's try an example: we'd like to put our own character set into a tiny 5K VIC. Things will get a little crowded, since we need to use 2K for the extra character set. But we can make it work.
Almost all the spare RAM memory of the computer is assigned to BASIC. This is to allow you to write programs as large as possible. We must take memory away from BASIC to make room for the new video stuff.
BASIC memory is a single continuous block. It goes from Start-of-BASIC (whose address is logged in locations 43 and 44) to Limit-of-BASIC (whose address is logged in locations 55 and 56). No breaks: you can't pop a screen in the middle and have BASIC memory skip around it. You can find the Start-of-BASIC address on your machine by typing PRINT PEEK(43) + PEEK(44)*256; or the Limit-of-BASIC address by typing PRINT PEEK (55) + PEEK(56)*256. Remember these; they are a good way to check the values after you've changed things around.
We have a choice. We can move down the Limit-of-BASIC, which will give us room at the top. We can move up the Start-of-BASIC, which will make room at the bottom. Or we can do both, if we don't mind the extra work. Whatever we do, we must realize that we're trimming back the area available for BASIC.
If we move down the Limit-of-BASIC, we must say CLR after we do so. This gets rid of variables and strings that might be in embarrassing places. Don't forget this.
Moving the Start-of-BASIC upwards takes a good deal of care. Rule 1: We must POKE a value of zero into the first available location. Rule 2: We must set the Start-of-BASIC pointer so that it points to the next location behind the zero. Rule 3: When we're finished, we must type NEW to make sure that BASIC is cleanly set up in the new memory area.
How do we set up these pointers? Divide the desired address by 256: the remainder goes into the first byte, and the quotient into the second byte. For example: we want to move the Limit-of-BASIC down to 6144. 6144 divided by 256 gives 24 with zero remainder, so we POKE 55,0:POKE 56,24:CLR.
Another example: we want BASIC to start at 5120. First, place the zero: POKE 5120,0. Now, the pointer must be set to 5121 (behind the zero); since 5121 divided by 256 gives 20 with a remainder of 1, we POKE 43,1:POKE 44,20:NEW.
We want to set up a complete character set, including the reverse characters. That will take 2K of memory — we could do it in 1K if we were willing to skip the reverse characters. Let's plan to put this at the top of memory, starting at block 14.
The screen takes up half a block, of course, and it seems to make sense to set this up just below the characters; so we'll pick block 13.5 (we can set the screen on a half-block boundary, remember?). This calls for a Limit-of-Memory of 5632. You may have noticed, by the way, that the Limit-of-Memory pointer is set one location beyond the last usable value. In other words, BASIC can use 5631, but it can't use 5632, the Limit value.
Arithmetic time. 5632 divided by 256 gives 22 with zero remainder; so type:
POKE 55,0:POKE 56,22:CLR
and the space is allocated. You can try PRINT FRE(0) and see what a puny amount of memory you have left.
We haven't yet told the video chip to use this area. We're not ready to point the chip towards the new character set area; we haven't put any characters there yet. So let's move characters in — but wait a moment.
The new character set would go over top of the present screen location. This would give us an odd-looking screen. We could live with that part, but the screen would also do odd things like scrolling, which would move the character set we had so carefully placed. We'd better move the screen to a clear area first.
Moving The Screen: Video And System
The character set can remain as block zero for the moment; we'll want to shift the screen to block 13.5, with POKEs to 36869 and 36866. But we need to do two extra things at the same time: tell the computer system where to find the new screen, and clean up the screen area.
The POKEs to 36869 and 36866 tell the video chip all it needs to know about delivering the screen memory to the video output circuits. But unless we tell the computer system about the change, it will continue to put new characters into the old screen area. We tell it with a POKE to location 648. Here's how the arithmetic goes.
Divide the new screen memory address by 256, and POKE the result into address 648. Our example puts the screen at 5632, which gives 22 when divided by 256; so we'll POKE 648,22. But we need to do everything together. Let's work out the other POKEs. The screen goes to block 13.5, and the character set remains at block zero for the moment. 13 times 16 plus 0 gives 208, so we'll need to POKE 36869,208. The half-block is logged into the system with POKE 36866,128 + 22, and so we move the screen with:
POKE 648,22:POKE 36869,208:POKE 36866,150: PRINT CHR$(147)
CHR$(147) is the clear-screen character, by the way.
Now we can copy the character set from its fixed appearance in 32768 to our planned new area at 6144 and up. If we copy the character set exactly, we've wasted a lot of memory; we'll get the same characters as before. To show we have control, we'll vary the normal character set slightly.
Instead of the normal graphics set — uppercase and graphics — we'll mix the two as we copy them over. Not too useful, perhaps, but when we cut over to the new character set, you'll be able to see that something new has happened. Enter the following program:
100 FOR J = 0 TO 255 STEP 2 110 J1 = J*8 120 FOR K = 0 TO 7 130 POKE J1 + K + 6144,PEEK(J1 + K + 32768) 140 NEXT K150 FOR K = 8 TO 15 160 POKE J1 + K + 6144, PEEK(J1 + K + 34816) 170 NEXT K 180 NEXT J
Run this program; it will take a minute or two.
The Final Touch
The screen has already been moved, and the character set is in place and ready to go. Let's cut it in, and the project will be complete.
The screen is still at block 13.5 and the new character set will be at block 14. So we do 13 times 16 plus 14 and get 222; we'll want to POKE 36869,222. Since we're not moving the screen this time, the "half-block" value in 36866 is still good, we won't need to change that. We're ready –enter:
Now try typing or listing the previous program, and look at the odd combination of characters we've created. We must tie things together neatly – BASIC, the Operating system, the video chip – to make it all work properly. But with good planning, we can make the screen do marvelous things.
Copyright © 1983 Jim Butterfield