I have recently given another go on my experiments on Commodore 64 BASIC programming. I like doing graphics even without specialized keywords. The Commodore 64 seems to have the flexibility required even with its native BASIC interpreter.
On this article I did a vertical scrolling of a chessboard. Now, it’s time to give a try to horizontal scrolling. As on previous experiments, scrolling registers will not be used.
Be sure to test the following programs on a stock Commodore 64 computer with no cartridge inserted, as some cartridges may affect the strict timing of these routines and cause flickering.
Horizontal scrolling is much more difficult, because you have to change all eight bytes of a given character to scroll it, on each frame. As you can see from my previous experiments, two different characters are only needed for a 1×1 chessboard. To scroll it vertically, two pokes were required. Now, for horizontal scroll, sixteen pokes per frame are theoretically required.
As it can be easily figured out, sixteen pokes on a frame are impossible to perform, so the routine will be quite slow. Still, since we are not using scrolling registers, we have to use hi-res mode. This is the only way to have a one pixel movement without using scrolling registers. Instead, if using scrolling registers or when moving sprites, it is still possible to achieve a one hi-res pixel movement even in multicolor mode.
The following program performs the chessboard scrolling by using sixteen POKEs. As you can see, it is very slow. For the sake of clarity, I tried to mimic as much as possible the algorithm used for vertical scroll in this article.
This program uses an array to update characters. Those values are precalculated to make things faster. Element with index 0 has only bit 7 turned on. Index 1 element has both bit 7 and bit 6 turned on, remaining bits are turned off. Index 2 element has bit 7, 6 and 5 turned on, remaining bits are turned off. And so on. This way, flipping between array elements allows for a horizontal movement.
To scroll the chessboard, if you start to fill a previously empty square, you also have to start to empty a previously filled square. So, if you turn on bit 7 on a character, you also have to turn off bit 7 of the nearest character to the right. So, if you poke the value 128 on a character, you will also have to poke the value 255-128 on the nearest character to the right. 255-128 makes 127. That means, you turn off bit 7 and turn on the remaining bits. Just the opposite as before.
Line 6 does just this, using variables F and G. Array element X(0) holds the value 128. If you consider the expression F-X(0), if F equals 0, resulting value is -128. If F is 255, resulting value is 127. So, on a given frame, we have to poke 128 on the bytes of a character, and the value 127 on the bytes of the nearest character to the right. This is accomplished by using the variables G and F and by letting F = 0 and G = 255. Note the use of the function ABS as you can’t poke a negative number on memory. After an 8 pixel scroll has been performed, values F and G are swapped. This way, a filled square will become empty again and an empty square will be now filled as well, so that the remaining part of the scroll will be performed.
Turning off and on single bits would be slower, that’s why we use this approach.
There is room for little optimization, but still, a 1000% speed improvement would be required to have a smooth motion. This is just impossible if we keep using POKEs.
Now, is there a fast way to put values in RAM in Commodore 64 BASIC? The answer is YES, and PRINT is what we need.
When BASIC prints something on the screen, it is actually putting screen codes in RAM. The standard video matrix starts from 1024 decimal and ends to 2023 decimal. It is possible to change the video matrix position. The VIC-II can use other memory areas for it.
But still, the KERNAL must know where the video matrix is located as well. Location 648 decimal contains the page number of current video matrix start address. Default content is 4 (256 * 4 = 1024).
As the programmable characters we use are located from 12288, we must poke the value 48 on location 648 (12288/256 = 48).
At this point, the screen code of any character we print will be stored on locations starting from 12288. We have an array of values: now we have to put those values in memory by using PRINT. To do that, we must figure out the characters having those values as screen codes. This is not always easy. I had some trouble figuring out what character had a 192 decimal screencode. This character cannot be directly obtained from the keyboard. It looks like SHIFT+C reversed, but is is a different character. It can be PRINTED by using PETASCII code 192, reversed.
Please also note that the value 224 is poked onto memory by printing the reversed shifted space character.
I directly coded an unrolled version of this program: it should be faster and easier to understand.
As you can see, this version is fast. It is roughly 1000% faster than the previous version. The program is still short. Note the HOME control key at the beginning of each PRINT instruction (reversed S): that is used so that values will be placed in memory starting from 12288 on each frame. It’s just like screen editing, but we are actually editing characters’ shapes by using PRINT.
Some static vertical bars are shown to demonstrate that scrolling registers are not used. That allows any static text or graphics to be shown along with the chessboards, no need for screen splits.
To stop the program, you can press RUN/STOP + RESTORE. But, that is not enough. As far as I can see, the related routine from the KERNAL does not restore the content of location 648 decimal. So, after pressing RUN/STOP+RESTORE, you have to do a little “blind typing” and issue the command POKE 648,4. This is what it is needed to gain control of the cursor again.
Now, this program shows that it is possible to use screen editing features to do hi-res graphics. This is made possible by the way the VIC-II chip was designed and by the flexibility of the Commodore KERNAL. This program only prints 16 characters and 3 control codes on each frame, but things are set up so that you have the illusion many pixels on the screen are moved.
On this article I improved the vertical scrolling algorithm so that a bigger chessboard could be scrolled vertically. Now, since “printing values” in memory is very fast, it is possible to scroll a bigger chessboard horizontally as well. I managed to scroll a 2×2 chessboard on roughly one third of the viewable screen area with no flickering. Only two characters must be changed on each frame, so the bytes that must not be changed are skipped by using the CRSR RIGHT. If you use PRINT to poke values in memory, the cursor control let you choose what locations to change and what locations to left unchanged. Again, this is the same as screen editing.
The code is unrolled to gain speed. As you can see, the program is longer than previous examples.
Code may be shortened by using string arrays and FOR… NEXT cycles, but program execution will be much slower and you will end up with flickers. The unrolled code seems to be the fastest solution.
The program is a bit complex, and of course routines like this one should be coded in assembly language. Still, I wanted to push the limits of BASIC a bit, and I was quite confident that the simple but fast C64 BASIC, coupled with the VIC-II chip and the versatile Commodore KERNAL would have made this task possible. Well, I wasn’t disappointed.
If you try to use different colors, for example white for static vertical bars and green for the chessboard, you will notice a problem: a part of the first line of the screen will have the same color as the chessboard:
This is due to the fact that color RAM cannot be moved. It is always located from 55296 to 56295 decimal. So, when we print values starting from location 12288, color codes are still “printed” from location 55296. So, we can still see the color codes of the characters being printed “out of the screen”.
The fix is easy: we just need to set the color back to white after the chessboard characters pattern has been printed. This is done in line 3 of the following program.