PORTING COMMODORE PET AND VIC-20 BASIC PROGRAMS TO KB9 ON THE PAL-1/microKIM (or, "What I learned over a few days fooling around with ANSI codes") by Dave Hassler, Nov. '22 The Takeaway: It really isn't difficult at all to port BASIC programs from PET to PAL. There are very few differences between KIM BASIC 9 and CBM BASIC v2 used on the VIC-20, and the C64 (the original Commodore PET 2001 used a CBM-patched version of KB9; "CBM BASIC v2" is essentially the "v4.0" version used on the later PETs). After all, Microsoft's Weiland, Davidoff, and Gates adapted KIM BASIC (both KB9 and KB6) and the first CBM BASIC from their BASIC-80 within a few months of each other. As long as a Commodore BASIC program (all versions) uses only cursor control keys to move around the screen, it's not too difficult to port it for use on a PAL-1 or microKIM (or even a real KIM-1, for that matter) that has KIM BASIC 9 available. And, it's not out of the realm of possibility even if the program *does* POKE to screen RAM, if you have 1K to set aside for a 40x25 array. GETTING STARTED There is a *wealth* of Commodore BASIC programs out there that will work quite nicely with the 16K+ expanded PAL-1 or microKIM. Zimmers.net, anyone? If the PET/VIC/64 BASIC program uses only cursor control characters and TABs to move around the screen, all one has to do is replace those printable characters with ANSI/VT100 "escape codes." A good MS-DOS utility to detokenize CBM BASIC programs and turn them into BASIC listing text files is CBM2ASC (use under DOSBox). Also, Droid64 is a Linux program/script for viewing .d64 files. It has edit, view BASIC/hex, copy, and a lot more (D64Editor is a Windows equivalent). It's handy, and the "save" while in View BASIC mode will output a text file that has "hex code symbols" (under UTF-8 encoding) that correspond to the cursor movement code characters. From there, I put both text files up on the screen in Mousepad (or whatever text editor you like), and start editing the file made with CBM2ASC or Droid64, comparing to the one made by Droid64. You can convert lowercase text files to all uppercase -- required by KB9 and TinyBASIC for keywords -- by: a) opening a terminal instance in the folder where the textfile/program listing resides; b) issuing the command 'dd if= of= conv=ucase' ... without the single quotes, of course. VIDEO "SCREEN" MANIPULATION Here's what I've sussed out, from the Droid64 output matched with PET program listings on the VICE emulator and from info in my trusty old VIC-20 "Programmer's Reference Guide": ASCII (PETSCII) Codes in Program Listings $11 = cursor down 1 position from current $12 = turn on "reverse" video $13 = place cursor at HOME position (top/left) $1D = cursor right 1 position from current $91 = cursor up 1 position from current $92 = turn off "reverse" video $93 = CLEAR screen, place cursor at HOME position $9D = cursor left 1 position from current ANSI/VT100 Equivalents *** all 'commands' prefaced with CHR$(27)+CHR$(91)+... where 'n' is the number of spaces to move, and 'n' defaults to '1') $11 = cursor down: "nB" $12 = "reverse" video: "7m" $13 = cursor to HOME: "H" (cursor to row 6, col 22: "6;22H") $1D = cursor right: "nC" $91 = cursor up: "nA" $92 = turn off "reverse": "m" (the general 'reset' code) $93 = CLEAR screen: "2J" $9D = cursor left: "nD" * often, it's necessary to postfix a ";" to the commands when you want to print something immediately. ** you can leave off the 'n' value if you just want 1. These codes will, often, be all that you need to port a PET program for use on the PAL-1 and KB9 ... that, and restructuring line length, which is best kept at 70 characters for KB9 (PET allows 80 and VIC-20 88, if I remember right). If your serial terminal emulator supports it, ANSI color control will make a lot of the VIC-20 non- (or simply-) animated BASIC programs look great, too. But I'll leave that to you to look up the color codes. VARIABLE VS. ABSOLUTE NUMBER IN ANSI CURSOR CONTROLS One issue I ran into, but was solved by my friend Nils A, is the variable problem. If the PET program does something like this: PRINT LEFT$(">>>>>>>>>",R+1) [> = cursor right] then you might think "Aw, man...there's a variable in there! That won't work, because the escape code requires a 'hard' number inside quotes for the option!" But here's how Nils showed me how to "plug in" a variable: R=13:R$=STR$(R):R$=MID$(R$,2):?ES$;R$+"C"; The MID$ function is the key: it slices off the first character, which is a space, and the escape codes do not like spaces. This method will substitute for trying to plug in a variable. THOUGHTS ON CBM PROGRAMS THAT POKE TO SCREEN RAM It would be easy enough, with 16K or 32K RAM expansion on the PAL-1, to simply dimension an array that's 40x23 (most games were written for the 40-column PET) within the BASIC program -- 23, to ensure that the "screen" does not scroll. From there, it would make sense to write a small ML program that printed the entire "screen" after issuing a CLEAR command (ES$;"2J") and then call that from within the BASIC program. Or, if you had drawn a static "board" or "field" on the screen, one could determine the position of the desired print location on the screen, and then use something like this to place the cursor in a "cell" of the screen, where R is row and C is column: 10 R$=STR$(R):R$=MID$(A$,2) 20 C$=STR$(C):C$=MID$(A$,2) 30 PRINTE$;R$;CHR$(59);C$;"H"; Another way would be to use loops: 5 ?ES$+"H"; 10 FOR Z=1 TO R 20 ?E$;"B"; 30 NEXT Z 40 FOR Z=1 TO C 50 ?E$;"C"; 60 NEXT Z Granted, this is slow. But without dedicated video memory and a video card on the PAL-1, you live with it. Hey, this is 1975 technology, people! :^) I suggest you run your serial terminal emulator as fast as the PAL-1 will allow, to make games more enjoyable. For me that's 4800 bps, but 9600 should be OK for some, too. STATEMENT, COMMAND, AND FUNCTION DIFFERENCES, KB9 vs CBM BASIC v2 NOTE: it is possible that your version of KB9 may be slightly different than mine; i.e., the addresses I mention below might be a tad different than yours [thanks to Nils A. for that point]. I use a KB9 version tweaked by Jim McClanahan specifically for the PAL-1 that fixes the backspace issue and makes it destructive; normally, it's more like the Commodore "cursor left." Plus, there's 'KB6' out there (v1.2), too. Although they are very close in function, syntax, nomenclature, etc., KB9 -- a.k.a. "MOS TECH BASIC V1.1" -- is two versions older than the Commodore v2.0 flavor, and there are bound to be a few differences in the commands. Here's what I've learned: 1. KB9 has an undocumented GET statement (it won't give a syntax error when encountered, as with KB6), but it doesn't work. You'll have to use INPUT. Typically, in the CBM program you'll see something like: 10 GET A$:IF A$="" THEN 10 A KB9 alternative is: 10 INPUT A$:A$=LEFT$(A$,1) or, in a test for certain input: 5 ES$=CHR$(27)+CHR$(91):UP$=ES$+"A" 10 INPUT A$ 20 IF LEFT$(A$,1)<>"Y" THEN PRINT UP$:GOTO 10 30 END 2. You could also get fancy and "blank" the retried input line with spaces and cursor manipulation, if you want to "erase" the previous input. Finally, both BASICs will break/halt program execution if a is entered alone at an INPUT prompt, and leave CHR$(13) in the variable. It's annoying at times, but can be turned off in KB9 with POKE 10920,169 (loc. 10688 for KB6). After that, KB9 will only stop execution with Control-C, or if it hits a STOP or END command. 3. CBM BASIC's PRINT TAB(x) is nondestructive, but KB9's *IS* and overwrites with spaces as it tabs. Change PRINT TAB(x) to "cursor right" if you need to preserve the display: PRINT TAB(14)"Test" = ?ES$+"14C";"Test" 4. You cannot print the @ or underscore as characters from within a string with KB9; you have to use PRINT CHR$(64) and CHR$(95), respectively. E.g., 10 PRINT "_" will print nothing, and 10 PRINT "@" will print a CRLF. 5. KB9 uses the USR(%addr) function to call a machine language program, instead of CBM's SYS statement. 6. KB9 has no provision for I/O other than the SAVE and LOAD commands, which only address the KIM monitor tape routines. The only easy mod is to stick Hypertape somewhere, say $0300, and change $275C in KB9 to JMP $xxxx, instead of to the regular save routine at $1800. In fact, you could change that $xxxx to point to *any* routine. Anyway, say you have a printer or disk drive or something hooked up to the second RIOT, and you have a little machine language program you call to pipe output to that. KB9 stores the starting address of a program at $0078 and $79 (little endian), and the end address at $7A and $7B and then stores those as normal in $17F5-8 before it calls DUMPT at $1800. Your I/O program could grab those addresses, ala Hypertape. You might also "hijack" KB9's pointer to the KIM OUTCH routine; it stores that address at $2A51, which you could change to point to your own routine and redirect output to a printer. Otherwise, any CMD and PRINT# statements in the Commodore programs have to go. 7. TI and TI$. These are reserved Commodore variables for the kernel's jiffy clock, which runs fairly close to actual time, in 1/60 seconds. TI$ references TI and returns a string "hhmmss". It can be defined, too: TI$="054322". KB9 does not have this, but the RIOT's jiffy clock is accessible (with and without interrupt) from $1744 through $174F, and those locations can be PEEKed from within BASIC.