Hooray for SYS
Harvey B. Herman
Department of Chemistry University of North Carolina at Greensboro
Greensboro, North Carolina 27412
The PET User's Club Newsletter (Vol. 1, Issue 3) reprinted an interesting article by Karl Hildon entitled "Probing PET's Memory". PETters were encouraged to experiment with the SYS command. Many of the routines in the PET are written as subroutines which terminate with the machine language instruction, RTS (return from subroutine). When a routine is initiated by the SYS command execution of the RTS instruction returns the PET to BASIC command mode or continues with the BASIC program. Using this idea we may be able to pick and choose useful segments of PET's Code and, in effect, make a new operating system.
This article describes three examples of tape operations which are not possible with just the normal BASIC commands. I hope readers will find them useful and are encouraged to develop similar ones on their own with the information supplied here. For convenience I have summarized in the Table the SYS calls and memory locations that I refer to in this article for both original and upgrade ROMs.
Occasionally I receive a tape of a machine language program with no information on its load limits. It is not possible to make a backup copy without this data. My first example is a BASIC program (see listing for TAPE DIRECTORY) which continually reads a tape and lists the start and end (+1) addresses for each program it finds. The idea behind this program and other examples here come from an article by Jim Butterfield, "Watching a Cassette Load", PET User Notes, Vol. 2, #1. He discussed several SYS commands in the article. The TAPE DIRECTORY program uses one of the SYS calls to load a tape header, containing among other information, the start and end addresses of the tape load. The addresses PEEKed from the beginning of the first cassette buffer are then converted to hexadecimal, using another Butterfield idea, and printed out. Note the use of the dynamic keyboard in statement 10 (cf., Mike Louder, "Best of PET Gazette") and the changes necessary for upgrade ROMs in statement 9.
More than once I have received a tape which would not load into my PET. For example, the program may have been saved from $4000 up in the originating PET and the highest location in my computer is $3FFF. My second BASIC example is a program (see listing for RELOCATE) which loads a cassette program into any area of RAM memory specified by the user. The loading addresses on the tape header are bypassed. I did the same trick manually in an article I wrote for MICRO ("MOVEIT", 16:17, with update 17:18). This program described here completely automates the procedure by using the dynamic keyboard idea. It asks for input of the starting location, loads the tape header, corrects the header information in the first cassette buffer, and completes the rest of the load. Note the changes necessary for upgrade ROMs (Statements 165, 330, and 345). After relocation machine language programs will probably need some changes to reflect the new location before executing successfully.
Appending one BASIC program to another is a very useful operation. The final BASIC example (see listing for APPEND) has appeared before in many different guises. For example, as a wedge (Commodore PET User's Club Newsletter, Vol. 1, #4-5, p. 24), or with a SYS call to a machine language program (PET User's Notes, Vol. 1, #7). The BASIC Programmer's Toolkit (Palo Alto ICs) also has a built in tape append function. The BASIC programs described here (APPEND and APPEND NEW PETS) uses a similar set of SYS calls as RELOCATE. The programs first determine the end of BASIC from pointers in page zero. After the header is loaded the start/end information in the tape buffer is updated to reflect a remaining load which starts at the end of the first BASIC program. The program can be run repeatedly to append as many programs as desired. However, each program should have successively higher line numbers with no overlap. The append program can be deleted manually after use or the task could be automated using the dynamic keyboard.
Several problems came up when I tried to adapt the append program for upgrade ROMs. Jim Butterfield was kind enough to send me the locations corresponding to "load next header" and "load rest of tape" However, the load next tape routine did not have exactly the same effect as in the older model PETs. The new routine did not correct the chaining (links between BASIC lines) and update various pointers (e.g., to end of BASIC program). My APPEND program for new PETs needed an additional SYS call to correct the chaining and a separate update POKE so BASIC can keep track of the larger merged program.
The examples given here were all for cassette tape operation. There is no reason why examples have to be limited to tape. In the future, I hope to read about other examples where selective parts of PET's code BASIC are utilized in BASIC programs. Most of us, including myself can understand BASIC more easily than machine language and as long as speed is not a requirement, I see no reason why we can't use the 14K bytes of code in ways never dreamed of originally.
TABLE (hex locations in parenthesis) | ||
Function | Original ROMs | Upgrade ROMs |
load header | 62894 (F5AE) | 62886 (F5A6) |
pointer to end of BASIC program | 124/125 (7C/7D) | 42/43 (2A/2B) |
Header Buffer | 635-638 (27B-27E) | same |
load rest of tape | 62403 (F3C3)* | 62393 (F3B9) |
correct chaining | 50224 (C430) | 50233 (C439) |
current device # | 241 (F1) | 212 (D4) |
LOAD/verify flag | 523 (20B) | 157 (9D) |
# Chars, in keyboard | 525 (20D) | 158 (9E) |
start of keyboard buffer | 527 (20F) | 623 (26F) |
Note: With original ROMs, the chaining is corrected and end of BASIC program pointer updated automatically after BASIC program load. With upgrade ROM, chaining and pointer update must be done manually.
2 REM TAPE DIRECTORY 5 REM HARVEY B. HERMAN 8 REM SET CURRENT DEVICE NUMBER TO TAPE 1 : LOAD NEXT HEADER USING DYNAMIC KEYBOARD 9 REM NEW PET-POKE212, 1 : SYS 62886 : POKE 158, 1 : POKE 623, 13 10 POKE 241, 1 : PRINT "↓↓↓SYS 62894 : GOTO20 ↑↑↑" : POKE525, 1 : POKE527, 13 : END 19 REM 635-638 TAPE BUFFER START AND END LOCATION 20 A = PEEK (635) : B = PEEK (636) 30 GOSUB 110 35 PRINT 40 PRINT "TAPE START"; 50 GOSUB 120 60 A = PEEK (637) : B = PEEK (638) 70 GOSUB 110 80 PRINT "TAPE END"; 90 GOSUB 120 100 GOTO 10 109 REM CONVERT HIGH/LOW BYTES TO LOCATION 110 C = 256*B+A : RETURN 119 REM DECIMAL TO HEX CONVERSION-JIM B. IDEA 120 X = C/4096 : FOR J = 1 TO 4 : A = INT (X) 130 IFA > 9 THEN PRINT CHR$ (A + 55); : GOTO 150 140 PRINT CHR$ (A + 48); 150 X = (X-INT(X)) * 16 : NEXT J : PRINT : RETURN
100 REM RELOCATE 110 REM HARVEY B. HERMAN 120 REM INPUT START OF RELOCATION 130 INPUT "PROGRAM START LOCATION"; C 140 REM CONVERT TO HIGH/LOW BYTES : SAVE FOR LATER 150 GOSUB 400 : SL = A : SH = B : NS = C 160 REM SET CURR. DEVICE NUMBER TO TAPE 1 : LOAD NEXT HEADER USING DYNAMIC KEYBOARD 165 REM NEW PET-POKE 212, 1 : SYS 62886 : POKE 158, 1 : POKE 623, 13 170 POKE 241, 1 : PRINT "↓↓↓SYS 62894 : GOTO 200↑↑↑" : POKE 525, 1 : POKE 527, 13 : END 180 REM 635-638 TAPE BUFFER START AND END LOCATION 190 REM FIND TAPE START 200 A = PEEK(635) : B = PEEK(636) 210 REM SAVE FOR LATER 220 GOSUB 380 : S = C 230 REM FIND TAPE END + 1 240 A = PEEK (637) : B = PEEK (638) 250 REM SAVE FOR LATER 260 GOSUB 380 : F = C 270 REM CALCULATE NEW TAPE END 280 C = NS + (F-S) : GOSUB 400 : FL = A : FH = B 290 REM CORRECT TAPE BUFFER START AND END 300 POKE 635, SL : POKE 636, SH 310 POKE 637, FL : POKE 638, FH 320 REM FLAG-0/LOAD, 1/VERIFY 330 POKE 523, 0 : REM NEW PET-157 340 REM LOAD REST OF TAPE WITH DYNAMIC KEYBOARD 345 REM NEW PET-SYS 62393 : POKE 158, 1 : POKE 623, 13 350 PRINT : PRINT : PRINT "SYS 62403↑↑↑ : POKE 525, 1 : POKE 527, 13 360 END 370 REM CONVERT HIGH/LOW BYTES TO LOCATION 380 C = 256 * B + A : RETURN 390 REM CONVERT LOCATION TO HIGH/LOW BYTES 400 B = INT (C/256) : A = C-B*256 : RETURN
100 REM APPEND 110 REM HARVEY B. HERMAN 120 REM SET CURR. DEVICE NUMBER TO TAPE 1 : LOAD NEXT HEADER USING DYNAMIC KEYBOARD 130 POKE 241, 1 : PRINT "↓↓↓SYS 62894 : GOTO 150↑↑↑" : POKE 525, 1 : POKE 527, 13 : END 140 REM 635-638 TAPE BUFFER START AND END LOCATION 150 A = PEEK(635) : B = PEEK(636) 160 GOSUB 400 170 REM SAVE TAPE START 180 S = C 190 REM FIND END OF BASIC PROGRAM 200 A = PEEK(124) : B = PEEK (125) 210 GOSUB 400 220 REM CALCULATE NEW START LOAD 230 C = C-3 : T = C : IF PEEK (635) = 0 THEN C = C-1 : T = T-1 240 GOSUB 420 250 REM CORRECT LOAD POINT 260 POKE 635, A : POKE 636, B 270 REM FIND TAPE END (+1) 280 A = PEEK (637) : B = PEEK (638) 290 GOSUB 400 300 REM CALCULATE NEW TAPE END 310 C = C-S 320 C = T+C 330 GOSUB 420 340 REM CORRECT END LOAD : SET LOAD/VERIFY FLAG TO LOAD 350 POKE 637, A : POKE 638, B : POKE 523, 0 360 REM LOAD REST OF TAPE WITH DYNAMIC KEYBOARD
370 PRINT : PRINT "↓↓SYS 62403↑↑↑" : POKE 525, 1 : POKE 527, 13 380 END 390 REM CONVERT HIGH/LOW BYTES TO LOCATION 400 C = 256*B + A : RETURN 410 REM CONVERT LOCATION TO HIGH/LOW BYTES 420 B = INT(C/256) : A = C - B*256 : RETURN
100 REM APPEND NEW PETS 110 REM HARVEY B. HERMAN 120 REM SET CURR. DEVICE NUMBER TO TAPE l : LOAD NEXT HEADER USING DYNAMIC KEYBOARD 130 POKE 212, l : PRINT "↓↓↓SYS 62886 : GOTO 150 ↑↑↑" : POKE 158, l : POKE 623, 13 : END 140 REM 635-638 TAPE BUFFER START AND END LOCATION 150 A = PEEK (635) : B = PEEK(636) 160 GOSUB 400 170 REM SAVE TAPE START 180 S = C 190 REM FIND END OF BASIC PROGRAM 200 A = PEEK(42) : B = PEEK(43) 210 GOSUB 400 220 REM CALCULATE NEW START LOAD 230 C = C - 3 : T = C : IFPEEK(635) = 0THENC = C - 1 : T = T - 1 240 GOSUB 420 250 REM CORRECT LOAD POINT 260 POKE 635, A : POKE 636, B 270 REM FIND TAPE END (+1) 280 A = PEEK (637) : B = PEEK(638) 290 GOSUB 400 300 REM CALCULATE NEW TAPE END 310 C = C - S 320 C = T + C 330 GOSUB 420 340 REM CORRECT END LOAD : SET LOAD/VERIFY FLAG TO LOAD 350 POKE 637, A : POKE 638, B : POKE 157, 0 354 REM UPDATE ALL POINTERS 355 POKE 42, PEEK(637) : POKE43,PEEK(638): CLR 360 REM LOAD REST OF TAPE AND CORRECT CHAINING WITH DYNAMIC KEYBOARD 370 PRINT : PRINT "↓↓SYS 62393" : PRINT "↓↓↓SYS 50233↑↑↑↑↑↑↑" 371 POKE158,2 : POKE623, 13 : POKE624,13 380 END 390 REM CONVERT HIGH/LOW BYTES TO LOCATION 400 C = 256*B + A : RETURN 410 REM CONVERT LOCATION TO HIGH/LOW BYTES 420 B = INT(C/256) : A = C - B*256 : RETURN