Jeffrey D. Partch
If you're a 64 programmer, or a 128 programmer who feels a little lost when you switch modes, this comprehensive utility is well worth adding to your library. "PFkey 64" makes many 128-specific features available when you are using BASIC 2.0 on the Commodore 64.
It's no secret that the Commodore 128's BASIC 7.0 is one of the most powerful BASICs available on any microcomputer. But the Commodore 64 is still very popular, and many 128 owners spend a significant amount of time computing in 64 mode. "PFkey 64" allows you to use many BASIC 7.0 features on the Commodore 64, including programmable function keys, reserved variables, disk drive commands, special functions, and a number of BASIC 7.0 utility commands.
PFkey 64 is written entirely in machine language, so you'll need to use "MLX," the entry program found elsewhere in this issue, to type it in. Please read all of the instructions for using MLX before you get started. You must make one temporary change to MLX before you begin entering the data for PFkey 64. MLX does not normally permit the entry of data at addresses which correspond to BASIC or Kernal ROM. However, a portion of PFkey 64 is designed to reside in RAM beneath BASIC ROM. Thus, you must disable MLX's address error-checking feature before you begin entering data. (If you don't, you'll get an error message when you try to begin entry.) To turn off the address testing, place a REM before the first statement in line 1040 of the MLX program. This is just a temporary patch for entering the PFkey 64 data; do not make this a permanant change to MLX.
When you first run the modified MLX program, you will be asked for starting and ending addresses for the data you'll be entering. For PFkey 64, respond with the following values:
Starting address: BF40 Ending address: CFFF
After you've entered all the data for PFkey 64 and have saved a copy, you can load it into memory at any time. (BASIC programs currently in memory will be preserved.) Use the syntax LOAD "PFKEY",8,1 for disk or LOAD "PFKEY",1,1 for tape. (If you saved the program with some other file-name, use that name in place of PFKEY.) To activate PFkey 64, simply type SYS 49152.
PFkey provides several kinds of enhancements to Commodore 64 BASIC: new commands, new reserved variables, new functions, and new DOS commands. Like other BASIC keywords, these can be typed in abbreviated form; see the table accompanying this article. Here is an explanation of each group of BASIC enhancements.
QUIT. This command disables PFkey 64 and reclaims the memory previously occupied by the PFkey code. It works in both program mode and direct mode. You should always use this command before loading another machine language program that occupies the same memory area as PFkey 64 (see "Program Notes" below). To restart PFkey 64, you must reload the program and use a SYS as described above.
BANK. The BANK command allows you to PEEK and POKE memory areas that are normally hidden from BASIC. This is done in part because PFkey itself occupies a substantial amount of the 64's memory; making other memory areas available compensates for the loss to some extent. BANK must be followed by a number in the range 0–4. For instance, BANK 0 resets the 64 to its normal memory configuration. Here is an explanation of all the BANK commands.
- BANK 0 is the normal configuration. This configuration is reset whenever the computer enters direct mode (when the READY prompt reappears after you exit a program, for instance).
- BANK 1 allows you to PEEK values stored in the RAM underlying the BASIC ROM (Read Only Memory) chip at locations 40960–49151.
- BANK 2 allows you to PEEK values stored in the RAM underlying the Kernal ROM at locations 57344–65535.
- BANK 3 affects only the POKE command, and allows you to POKE into areas used by PFkey itself. (See "Program Notes," below.) You should rarely, if ever, have to do this, but the capability is there for advanced programmers.
- BANK 4 allows you to read the character shape data stored in ROM at locations 53248–57343.
SYS. Although it is not a new command, SYS has been modified to work as it does in BASIC 7.0. If you supply additional values after the address parameter, SYS stores those values in the processor's internal registers. Here is the syntax to use:
SYS address, A, X, Y, status
The last four parameters are optional and can be used to store values in the A register, X register, Y register, and status register, respectively. This assumes, of course, that you are calling a machine language program that expects those registers to contain certain values. The SYS command accepts any number or numeric variable in the range 0–255 for these parameters. It's not necessary to supply values for all parameters, but to specify a value for any parameter, you must supply values for all preceding ones. For example, if you wish to supply a value for the Y register, you must also provide values for the A-register and X-register parameters, but it is not necessary to provide a value for the status register.
RREG. The RREG (Read REG-isters) command returns the values of the processor's internal registers. One use for this command is to pass information from a machine language routine back to BASIC. The registers are read in the same order as that used for SYS. (See above.) Here is the basic syntax:
RREG var1, var2, vat3, var4
You can use any numeric variable for the four parameters. For instance, the command RREG AR, XR, YR, SR assigns the contents of the A, X, Y, and status registers to the variables AR, XR, YR, and SR, respectively.
KEY. This is one of the most versatile and useful commands provided by PFkey 64. With it, you can assign commands to any of the computer's function keys. As on the 128, default commands are assigned when you first run PFkey. To display a list of the current function-key assignments, type KEY and press RETURN without typing anything else. You also can create your own function-key assignments, using this general syntax:
KEY number, command$
The number parameter tells PFkey which function key to define; this must be a value in the range 1–8. The command$ parameter must be a string containing the command or commands you wish to assign to that function key. For instance, say that you want function key fl to execute these commands each time you press it:
The first command prints a CLR/HOME character, which clears the screen, and the second lists the program in memory. These commands assign this definition to the fl key:
A$ = "PRINT CHR$(147):LIST" + CHR$ (13) KEY 1, A$
Note that we added a carriage return (character 13) to the end of the command string A$. This causes the computer to "press RETURN" at the end of the command. In some cases, you might not want a carriage return; for example, in a load command, you might want the computer to first print LOAD followed by one set of quotation marks, and then to allow you to type in the rest.
You can use the CHR$ function to include any nonprinting characters, such as quotation marks, in the command string. The command string can be a single BASIC statement or several BASIC statements. However, BASIC itself limits the length of an input line to 80 characters, so you should not attempt to create a function-key definition longer than that.
DELETE. This command deletes a single program line or a range of program lines. Here are two simple examples:
DELETE 100 DELETE 100–200
The first command deletes line 100 from the program in memory. The second command deletes every line from 100 to 200, inclusively. This command works only in direct mode (when you're not running a program) and does not accept numeric variables in place of line numbers. You must always specify two line numbers for a range (for example, DELETE—100 is invalid), and the command does not work unless both line numbers in the specified range exist.
HELP. This command provides a shortcut for locating program errors. When a program stops with an error, type HELP and press RETURN. PFkey 64 lists the line where the error occurred and highlights the erroneous statement in reverse video. (In a few cases, the statement which generates the error is not itself wrong. For example, while it READs values from DATA statements and POKEs the values into memory, a program might stop with an ILLEGAL QUANTITY error in the line that contains the POKE. But the illegal quantity is actually contained in the DATA value which the computer was reading at the time.)
AUTO. The AUTO command eliminates the drudgery of typing line numbers by hand as you enter a program. To turn on automatic line numbering, type AUTO followed by an increment value in the range 1–63999. As soon as you press RETURN at the end of a program line the computer automatically types the next line number. For instance, this command causes the computer to print line numbers in increments of 10:
If you execute a direct-mode statement, or press RETURN on a blank line, the computer suspends automatic numbering until you enter another program line. Automatic line numbering is turned off if you type AUTO and press RETURN without typing anything else, or when you run any program.
RENUMBER. This command renumbers the BASIC program in memory. It can be used in two different ways. If you simply type RENUMBER and press RETURN, PFkey renumbers the first line of the program as line 10 and renumbers all remaining lines in increments of 10 (the second line is 20, the third is 30, and so on). You can also specify the initial line value, the increment, and the line on which to start renumbering. Here is the general syntax:
RENUMBER newline, increment, oldline
For instance, this command tells PFkey to start at existing line 200, renumbering that line with the new number 1000, and numbering all successive lines in increments of 20:
RENUMBER 1000, 20, 200
The RENUMBER command operates only in direct mode and does not accept variables in place of its parameters. This command renumbers all internal references preceded by GOSUB, TRAP, RESUME, RUN, THEN, GOTO, GO TO (as two keywords), and ON GOTO. RENUMBER stops without harming the program if the renumbering would create a reference to a non-existent line, create a line number higher than the legal limit (63999), corrupt the chronological order of program lines, duplicate an existing line number, or create a program too large for PFkey's memory.
TRAP, RESUME. These closely-related commands allow you to respond to many BASIC errors that would otherwise cause a program to stop.
TRAP permits you to regain control of the computer when a BASIC error would normally cause execution to cease. TRAP must be followed by the number of the program line where you want to branch when a BASIC error occurs. For instance, the statement TRAP 5000 causes the computer to branch to line 5000 whenever any error occurs. At line 5000, you would place the routine that takes whatever action is necessary to correct or respond to the error.
The RESUME command allows you to reenter the main program after executing a TRAP routine. This command can take either of two forms:
RESUME NEXT RESUME linenumber
The command RESUME NEXT causes the computer to resume execution at the statement immediately after the one which triggered the error. You ordinarily would use this syntax for errors that can be cured completely by the TRAP routine. The second form of trap allows you to branch to the line specified by linenumber. This option is appropriate for more serious situations—for instance, when an error requires that you terminate the program completely or restart it, rather than continue where the program left off.
Both TRAP and RESUME are valid only in program mode, and neither command accepts variables as line numbers or nonexistent line numbers. Keep in mind that TRAP and RESUME turn each other off. In other words, TRAP is not reinstated automatically after a RESUME; if you wish to turn error trapping back on after RESUME, you must do so with a second TRAP statement. Similarly, RESUME is invalid unless a TRAP is in effect; executing RESUME before you perform TRAP, or executing two RESUMES in a row, causes an error.
TRAP and RESUME are very useful for catching errors, particularly in programs designed for beginners or unsophisticated computer users. However, most programmers wait until a program is finished and debugged before inserting TRAPs. In that way, you can prevent a TRAP from confusing you, the programmer, unnecessarily.
TRON, TROFF. This pair of related commands turns trace mode on and off. TRON (TRace ON) turns the trace feature on, while TROFF (TRace OFF) disables it. Neither command accepts any parameters. When a program is running in trace mode, the current line number is listed just prior to the execution of each new statement. Although there are limitations to this method—the trace display occupies the same screen that may be used for your program's output, and may not be visible at all if the computer is not in text mode—this feature can be quite useful if you suspect a problem with a program's logic.
PFkey 64 provides you with four reserved variables taken from BASIC 7.0. You already may be familiar with ST, TI, and TI$, which are reserved variables in BASIC 2.0. Reserved variables are set aside for the computer's own use and cannot be assigned a new value with LET, GET, or any other BASIC assignment statements. Keep in mind, however, that this limitation applies only to variables of the same type. For example, although the floating-point variable EL is reserved (see below), you can still use the string variable EL$, the integer variable EL%, and so on, because BASIC can distinguish those variables on the basis of their types.
All of the new reserved variables are reset to their default (normal) values after you execute a CLR command, or perform any action that edits a program. Here is a list of the reserved variables:
EL, ER. These two numeric variables are particularly useful in TRAP-handling routines. EL (Error Line) stores the number of the program line where the most recent BASIC error occurred, and ER (ERror number) holds the error number for the most recent error.
DS, DS$. This pair of reserved variables holds information about disk operations. The string variable DS$ holds the text of the most recent error message from the disk drive command channel, while the numeric variable DS holds the error number for the most recent disk error. The next time the error light starts to blink on your drive, try typing PRINT DS,DS$ and pressing RETURN. If DS equals 0, and DS$ prints OK, the drive's status is normal.
Like all BASIC functions, the new functions provided by PFkey 64 require some additional information inside parentheses.
HEX$. This function converts decimal (base 10) numeric values into their hexadecimal (base 16) equivalent. The number inside parentheses must be in the range 0–65535. For instance, the statement PRINT HEX$(255) yields 00FF. Note that the result is returned as a string four characters long; after you execute X$ = HEX $(254), the string X$ contains the four-character string 00FE.
DEC. The DEC function does the opposite of HEX$, converting a hexadecimal string into a decimal numeric value. Again, the value must be in the range 0–65535. DEC accepts either string variables or literal strings. For instance, after you execute the statement X = DEC ("FF"), the numeric variable X holds the value 255. You do not need to supply leading zeros for a hex number of less than four digits; for example, DEC("FE") works just as well as DEC("00FE").
ERR$. The ERR$ function prints the text of BASIC error messages. It is especially useful in conjunction with the reserved variable EL and the commands TRAP and RESUME. (See above.) You must supply ERR$ with a numeric value in the range 1–31 (error 34 is also valid). A typical use of this function is to display error messages from within a trap routine. To demonstrate this function, enter NEW in direct mode, followed by NEXT; then enter this line in direct mode:
PRINT ER, ERR$(ER)
POINTER. The POINTER function expects you to supply the name of a variable used in the current program. It returns the memory address where that variable's descriptor can be found. For instance, the statement ADDR- = POINTER(X) assigns to the variable ADDR the address of the variable X's descriptor. This function is useful primarily to advanced programmers who wish to examine how a particular variable is stored internally. If the variable has not yet been used, POINTER returns a zero. The variable's name is located in the two bytes immediately preceding the returned address. Be careful when using array variables, because this function creates a new, single-dimension, 11-element array if you have not previously performed DIM. Dan Heeb's book Tool Kit: BASIC (available from COMPUTE! Books), contains a detailed description of the structure of BASIC variable descriptors.
XOR. This function requires two numeric values in its parentheses. It performs an exclusive OR operation on the bits of the first value, using the bits in the second value. Both values must be in the range 0–65535. For instance, the statement PRINT XOR(1,255) yields 254.
PFkey supplies several new commands which simplify the use of a floppy disk drive. These differ from the commands available in BASIC 7.0 because no provision is made for a double disk drive (two disk drives in one case, which are addressed as drive 0 and drive 1). All of the current Commodore disk drives—the 1541 and 1571—are single drive units which are addressed as drive 0.
The allowable range of device numbers for these commands is from 8 to 31. The normal device number for a single Commodore drive is 8. The default drive is the last device used in the current session; if for some reason that number falls outside the range 8–31, it is reset to 8, the normal device number for a Commodore disk drive.
Every DOS command can be used in two forms. If your drive is device 8 (the usual situation), simply enter the command, followed by whatever information is indicated in the explanation for that command. If you have more than one drive, you can access the second drive (which will have a different device number) by adding, U and a device number to the end of the command. For instance, the normal syntax for the DIRECTORY command is to type DIRECTORY and press RETURN. However, you would use the command DIRECTORY,U9 to get a directory of the disk in device 9. This optional syntax can be used with all DOS commands.
All of these commands open the disk drive command channel (channel 15) during execution and close it when they finish. Thus, you always must close the command channel (15) before using any of these DOS commands.
In direct mode (when you are not running a program) all DOS commands that would alter the contents of a disk require confirmation before the command is carried out; the computer prints ARE YOU SURE? and does not carry out the command unless you press Y and then press RETURN. If you have more than one drive in your system (for instance, one which is device 8 and another which is device 9), it is strongly suggested that you include the device number wherever appropriate.
DIRECTORY. If you learn only one DOS command, this should be the one. DIRECTORY lists the directory of the current disk in the specified drive, without altering the program in memory. In other words, you no longer have to use the familiar LOAD "$0",8 command to view the directory.
COLLECT, This command recovers disk sectors which have been temporarily lost as a result of repeatedly scratching and resaving files. (This operation is also called validation.) You should perform an immediate COLLECT whenever you discover an unclosed (splat) file on a disk, which is signaled by an asterisk (*) next to the filename in the disk directory.
SCRATCH. This command erases the specified file or files from a disk. For instance, SCRATCH "TEST" removes the file TEST from the current disk. This command accepts variables in place of literal strings; for instance, both of these commands accomplish the same thing:
SCRATCH "TEST" A$ = TEST:SCRATCH A$
You can also use wild-card characters to scratch more than one file. For instance, SCRATCH "TEST*" deletes the files TESTFILE, TESTER, and any other file beginning with the characters TEST. The disk drive manual contains more information about DOS wild cards. Do not use SCRATCH on any disk that contains an unclosed (splat) file; use COLLECT (see above) on the disk immediately.
RENAME. The RENAME command changes the name of an existing file. For instance, this command renames the existing file OLDFILE with the mew name NEWFILE:
RENAME "OLDFILE" TO "NEWFILE"
The contents of the file are not changed by RENAME.
COPY. This command creates a duplicate of an existing file on the same disk. The original file is left unchanged. For instance, this command creates a new copy of the existing file TEST, naming the new file COPYOFTEST:
COPY "TEST" TO "COPYOFTEST"
DCLEAR. The DCLEAR command closes all open files and channels on the specified drive. The drive is reset to its power-on state, and the current disk is initialized. It's a good idea to enter this command every time you perform a disk swap, to make sure the drive knows it's dealing with a different disk.
HEADER. This command formats a disk. Before using a new disk for the first time, you must format it to mark off storage zones for the drive to use. The HEADER command can take two forms. Use this syntax if you are formatting a disk that has never been used before:
The name inside quotes must be no more than 16 characters in length. The disk ID can be any two characters; it is important that every disk have a unique ID. For instance, this command formats a new disk with the name WORKDISK, giving it WD as a disk ID:
If you are formatting a previously formatted disk (for instance, to erase its contents), you can omit the ID from the command. This command removes all the files from a previously formatted disk, giving it the name MYDISK:
Of course, you can also use the first syntax on a previously formatted. Use care with HEADER, since it effectively destroys all information that a disk might have contained before.
VIEW. You can consider this command a bonus, since it doesn't appear in either BASIC 7.0 or BASIC 2.0. It allows you to view a program file without disturbing the program currently in memory. This is very useful when you need to refer to a second program quickly and do not wish to save and reload the program you are working on. This command, for instance, displays the contents of the program file named MYPROG:
VIEW displays correctly all BASIC 2.0 keywords, as well as the BASIC 7.0 keywords that are added by PFkey 64. However, it does not recognize other BASIC 7.0 keywords that PFkey 64 does not support (BUMP is one example).
PFkey 64 uses the memory areas from locations 40448–40959, 49152–53247, and 679–767. You should not attempt to use other utilities or programs that make use of those memory areas. The first area is also used by the computer itself whenever you open a channel to the RS-232 device (a modem or serial printer). If you wish to use PFkey 64 with programs that open the RS-232 channel, install PFkey 64 first, and then load and run the program that accesses the RS-232 device. The program also creates four variable descriptors when it is installed. To help protect against crashes, PFkey 64 modifies the POKE command to produce an ILLEGAL QUANTITY error when you to change the contents of memory areas used by this program.
Those PFkey 64 keywords that are equivalent to BASIC 7.0 keywords are tokenized just like in BASIC 7.0. Thus, a Commodore 64 program that uses PFkey 64 statements like RREG or TRAP will also load and run properly on a Commodore 128. Likewise, a Commodore 128 program using these keywords will work, load, and run on a 64 with PFkey 64. A very significant exception is that the BANK statement performs a very different operation in PFkey 64 than it does in BASIC 7.0. You should also be aware that PFkey 64 supports only a few of the added features of BASIC 7.0. Thus, it will not allow all 128 programs to be run on a 64—just those that use the BASIC 7.0 statements specifically supported by PFkey 64.
Please refer to the "MLX" article in this Issue before entering the following program.
PFkey 64 Quick Reference
This table lists the abbreviations for every PFkey 64 keyword. It also shows the mode in which a command or function can be used. The abbreviation PRG means that a command works only in program mode, while DIR means that it works only in direct mode (when you're not running a program). ALL means that it works in both program and direct mode. The token value indicates the one- or two-byte value used to represent the keyword internally within a program line.
|AUTO||A shift-U||DIR||$DC (220)|
|BANK||B shift-A||ALL||$FE 02 (254 02)|
|COLLECT||COL shift-E||ALL||$F3 (243)|
|COPY||CO shift-P||ALL||$F4 (244)|
|DCLEAR||DCL shift-E||ALL||$FE 15 (254 21)|
|DELETE||DE shift-L||DIR||$F7 (247)|
|DIRECTORY||DI shift-R||ALL||$EE (238)|
|ERR$||E shift-R||ALL||$D3 (211)|
|HEADER||HE shift-A||ALL||$F1 (241)|
|HELP||H shift-E||ALL||$EA (234)|
|HEX$||H shift-E||ALL||$D2 (210)|
|POINTER||PO shift-I||ALL||$CE 0A (206 10)|
|RENAME||RE shift-N||ALL||$F5 (245)|
|RENUMBER||REN shift-U||DIR||$F8 (248)|
|RESUME||RES shift-U||PRG||$D6 (214)|
|RREG||R shift-R||ALL||$FE 09 (254 09)|
|SCRATCH||SC shift-R||ALL||$F2 (242)|
|TRAP||T shift-R||PRG||$D7 (215)|
|TROFF||TRO shift-F||ALL||$D9 (217)|
|TRON||TR shift-O||ALL||$D8 (208)|
|VIEW||VIshift-W||ALL||$FE 06 (254 06)|
|XOR||X shift-O||ALL||$CE 08 (206 08)|