VIC-20/64 Translations: Reading The Keyboard
When I bought my Commodore 64 computer, I recognized that there was very little software written expressly for my machine. But, because of its similarity to the VIC-20, I thought it would be possible to modify most – if not all – VIC programs with minimal effort to run on my computer, too.
A considerable number of locations used by the machines for internal workings are identical in both VIC and 64 memory maps, especially the first several hundred locations up through 831. The cassette buffers are given to location 1019, but some of the 64 sprites use memory from 832 to 1022, so this area is not directly compatible in most cases.
Also, even though the addresses are different, a number of locations seem to be used for the same purpose (excluding the screen and sound processing logic, of course). I recognized that the contents of many of these locations would be different, especially those holding addresses of memory limits and the like, but I expected that all of the differences would be straightforward, easily understood changes.
While a great many changes are straightforward, I quickly found a few locations that were not working in the same manner in both machines. Since it will be some time before I walk through enough VIC programs to hit all of the differences that exist, I decided to acquaint some 64 owners immediately with some of the pitfalls I discovered in my VIC to 64 translations. At least this will make you more cautious and keep you from wondering if your machines are broken when you get some weird results.
Hidden Keyboard Differences
In COMPUTE!'s First Book Of VIC, the article "Extended Input Devices: Paddles And The Keyboard," by Mike Bassman and Salomon Lederman, explains how the paddle works and how the VIC-20 handles its keyboard input logic, using the "polled" keyboard concept. This was one of my first translation attempts, since it seemed so easy to translate to the 64. After all, the keyboards of both machines are identical, right?
After a little work, I altered the VIC programs 2 and 3 in the article to programs 1 and 2 here. The differences are minor – I used a comma instead of a semicolon in the key code PRINT statement, for example. The hardest part was handling location 808 to turn off the RUN/STOP key's BASIC program BREAK effect. In the VIC, the normal value of this location is 112, but in the 64 it has a normal value of 237.
Changing this location to other values caused some problems until I found that setting it to zero seemed to work. I have no idea if this affects some other portion of the operating system, so the use of zero may not be universally correct.
Once it was written, I fully expected the keyboard matrix table of my 64 to be identical to that of the VIC. When I ran the program, however, I got considerably different results. I double-checked my program several times and could not find any mistakes, so I decided to compile my own 64 keyboard matrix table and see how things differed. Table 1 is the result. Note that the entire table is a transposition (axes swapped) of the VIC matrix with a couple of rows and columns rear-ranged. Apparently, the 64 designers wanted the RUN/STOP key to be in the upper left corner (127,127), so they made extensive changes for this and perhaps other reasons.
Once I realized that the polling values were different, I rewrote a VIC program which PEEKed into memory to read the character codes where they are stored. The program reads the character codes in location 197 as set by the BASIC program after BASIC has done its own polling of the keyboard. This location has the same meaning in the 64 as it has in the VIC.
At line 5 I added a POKE 808,0 to disable the STOP key's BREAK effect and thus allow me to find out its character code. As with the VIC, the SHIFT keys, the CTRL key, the COMMODORE key, and the RESTORE key have no effect on the value in location 197 – which is 64 when no key is being pressed. My version of the PEEK program has the values running continuously up the TV screen in four columns, just like the version of the polling program that I used.
64's Hierarchy Of Keys
As suspected, the character codes were scrambled when compared to the VIC codes — in only a couple of cases were they the same. Table 2 shows the Commodore 64 character codes for each key. There is also a definite hierarchy in the keys so that if two or more are held down simultaneously, one of them always takes precedence unless an even higher-precedence key is added to the group. The character code number seems to be the order of precedence, with the higher number overriding any lower character number if both are pressed — RUN/STOP has the highest precedence in Table 2 and overrides any other key or keys.
If RUN/STOP is held down after another key has already been pressed and held, it won't cause a BREAK in those cases where the row select code in Table 1 is the same for the two keys when location 808 is returned to the normal 237 value. Apparently, the RUN/STOP key has been "fail-safed" to keep it from BREAKing a program unless the RUN/STOP key, and only the RUN/STOP key, is hit.
The above examples should make it very obvious that there are a number of subtle, but still critical, differences between the Commodore 64 and the VIC-20. Who would have imagined that they would change the keyboard logic when both machines use identical keyboards? Caution is definitely in order.
I now know of the following categories of VIC-20/Commodore 64 differences:
- Screen and sound chip locations and related logic.
- Sprite data storage and logic (VIC-20 has no sprites).
- RAM areas (location, not contents — Commodore 64 is much larger here).
- ROM operating system logic areas (VIC-20 has a larger operating system).
- Contents of lower memory BASIC/operating system working areas (limit-of-memory registers and so forth in locations 0-831), though most will be straightforward changes from the VIC-20 contents (perhaps there are more differences such as the one in location 808).
- LOAD/SAVE procedures (VIC-20 is considerably less complex, but this is one of the things that requires its extensive operating system memory area).
- Keyboard polling values (Table 1) and character codes (Table 2).
- Extra built-in joystick port and extra TV RF output in addition to the NTSC color monitor
How To Read Table 1:
The key code value is set into location 56321 when the indicated key is hit and that key's row has been previously selected by POKEing row select code into location 56320; otherwise, the value of 255 will be in location 56321. The indicated value will remain set as long as the key remains depressed. (Commodore 64 keyboard hardware does the setting automatically.) If more than one key in a row is hit simultaneously, the key codes are ORed together.
Key Code (for PEEK) Returned From Location 56321 ($DC01) (Contents of Location 56321 = 255 Otherwise)
Legal Keyboard Row Select Code Values (Must Be POKEd Into Location 56320 ($DC00))
output port (lots of tricks probably possible with these!)
Other hidden differences are probably waiting for the unwitting Commodore 64 owner to stumble over when he wants to use a VIC program. I hope that anyone who does find some will write in to tell the rest of us.
Machine Language Program To Capture Key Code Before Changed By BASIC. (Incorporated as a BASIC loader in Program 2.)
Note: Change 127 ($7F) to any of the other legal row select values, depending on the key used. See Table 1. The routine is needed because the BASIC interpreter is continually changing the row select value to 127 to check for a STOP input from the keyboard at the end of every command, so we must grab the key code for our key by setting the desired row select and saving our key code for that row before the end of any BASIC instruction. It is used in Program 2, and it can be used in any program you create to check for keyboard inputs.
Note: Higher values of the CHAR CODE override lower values if two or more keys are pressed simultaneously. If any key in the 127 row of Table 1 is held down prior to pressing the RUN/STOP key, location 197 will change to 63 but a BREAK will not occur.
Disable RUN/STOP Key And PRINT Key Code Of Pressed Key(s)
Note: You will probably want to delete REM statements when you key this in. Also, putting 0 in location 808 works, but this is an important location and a value of 0 might not be correct for every program.
5 POKE 808, 0 : REM NORMAL VALUE = 237. DISABLES RUN/STOP WHEN = 0. 8 REM LINE 10 CUTS OUT 21 BASIC RAM LOCATIONS 10 POKE 51, 235 : POKE 52, 159 : POKE 55, 235 : POKE 56,159 20 FOR K = 0 TO 11 : READ X : POKE 40940 + K, X : NEXT : REM LOAD MACHINE LANGUAGE 30 SYS 40940 : REM CALL MACHINE LANGUAGE PROGRAM—SAVES KEY CODE IN 40959 40 PRINT PEEK(40959), : REM PRINTS 255 UNTIL KEY(S) IN SELECTED ROW ARE HIT 50 GOTO 30 : REM KEEP PRINTING UNTIL MACHINE TURNED OFF (STOP IS DISABLED) 60 DATA 169, 127, 141, 0, 220, 173, 1, 220, 141, 255, 159, 96 : REM MACHINE LANGUAGE 70 REM ML PROGRAM TO SAVE KEY CODE LOADED INTO LOCATIONS 40940-40951