Some Similarities Between Applesoft And PET BASIC
Garry Kiziak
Burlington, Ontario
I wonder how often a PET owner will pick up a magazine article and seeing that it applies to the Apple say "Oh! This isn't of any use to me.". Similarly, how many Apple owners will pick up a PET article and say the same thing? In fact, there is much to be learned about the PET from Apple articles and vice-versa. In many cases translating a useful utility or idea from the one computer to the other simply involves chaining a few addresses or some simple modification.
For example, a very useful idea appeared in Volume 3 Issue #1 of The Transactor dealing with the idea of reading data from a particular DATA statement. The following short PET program demonstrates how it works.
10 DATA FIRST, SECOND, THIRD 20 DATA FOURTH 30 READ A$, B$ 40 POKE 62, PEEK(119) : POKE63, PEEK(120) 50 READ A, B 60 DATA 1, 2, 3, 4 70 PRINT A$, B$, A, B
In this program, line 40 causes the READ statement in line 50 to get its data from the next DATA statement (i.e. line 60) instead of from the next data item which would have been in line 10.
To get this program to work on an Apple, it is only necessary to change the addresses in line 40. The following will do the trick.
40 POKE 125, PEEK(184) : POKE 126, PEEK(185)
In COMPUTE!, May, 1981, #12, Craig Peterson offered an elegant routine for the Apple that would allow you to input anything into a string (including commas, colons, etc.) without getting the EXTRA IGNORED error message. That routine is reproduced here.
1000 CALL 54572
1010 FOR B = 512 TO 751 : IF PEEK(B) <> 0 THEN NEXT
1020 IN$ = "" : POKE PEEK(131) + 256 * PEEK(132) + 1, 0 : POKE PEEK(131) + 256 *
PEEK(132 + 2, 2 : POKE PEEK(131) + 256 * PEEK(132), B - 512 : IN$ = MID$(IN$, 1) : RETURN
Once again, to get this to work on the PET, certain addresses will have to be changed. The necessary changes are as follows:
1000 SYS 48117 1010 FOR B = 512 TO 592 : IF PEEK(B) <> 0 THEN NEXT 1020 IN$ = "" : POKE PEEK(68) + 256 * PEEK(69) + 1, 0 : POKE PEEK(68) + 256 * PEEK(69) + 2, 2 1030 POKE PEEK(68) + 256 * PEEK(69), B - 512 : IN$ = MID$(IN$, 1) : RETURN
Notice that line 1020 had to be split into two lines. This is because the maximum length of a line in PET BASIC (including line numbers) is 80 characters. On the Apple, it is 239 characters.
The use of this subroutine instead of the traditional INPUT statement on the PET has an additional advantage – an empty response (i.e. simply pressing <RETURN>) does not break out of the program. Instead, the program continues and IN$ = "".
The above routine will prompt with a question mark and then a flashing cursor just like the regular INPUT statement. If you would rather that the question mark did not appear, then simply change line 1000 to:
1000 SYS 46306
Of course, not all programs will be as easy to change, but many will – even machine language programs. The trick is to find the correct change of addresses.
Recently, while writing a program for the Apple to draw the graph of practically any curve, I found it necessary to write a short machine language program which would change a line in the program to whatever you wanted. Specifically, it would be used to enter the equation of the curve to be graphed without going through the process of stopping the program, entering a new line, then typing in GOTO 550 or some similar process. This CHANGE routine would allow you to enter the equation just like in a regular INPUT statement. An assembly listing of the program is given below (Program 1). Here is an example of a machine language program that can be easily modified for the PET. The modified assembly listing is given in Program 2. Notice that the only changes required are in the addresses to the external ROM routines or zero page locations and to the IOSAVE and IOREST ore routines of the Apple which had to be simulated on the PET.
To illustrate how this routine works on the PET, get into the monitor (i.e. SYS 4) and type in .M 033A 0399. Then use the cursor to edit the displayed screen as indicated in the memory dump in Program 3. Get back inth BASIC and type in the short program in Program 4. RUN it, type in anything that you want, and watch line 100 change. RUN it again as often as you like and line 100 changes to whatever you dictate.
Now RUN the program again, but this time type in X = T : Y = SIN(T) in response to the prompt. Notice the momentary display of the message EXTRA IGNORED. In the listing you will see that line 100 has been changed correctly, but IN$ is only equal to X = T. If you happen to need the correct value of IN$ later on in the program, this would be totally unacceptable.
Now type in Program 5, RUN it, and type in your responses as before. This time, when you type in X = T : Y = SIN (T), you will notice that line 100 gets changed correctly as does variable IN$.
A good question would be: "How do you know what to change the various addresses to?". Personally, I have found two excellent sources. The first is the article "Applesoft Internal Entry Points" which appeared in the original Apple Orchard. The second source is the PET/CBM Personal Computer Guide (second edition). Page 476-493 have Hex Addresses and Label References for most of the zero page addresses and ROM routines in the new BASIC 4.0 (and BASIC 3.0) ROMs. Even most of the names of the routines from these two sources are the same. So, the next time you see an Apple article or a PET article, don't put it off as not applying to you, make it work for you and learn by the experiences of others.
Program 1.
SOURCE FILE : CHANGE - APPLE
----- NEXT OBJECT FILE NAME IS CHANGE -
APPLE.OBJ0
0341: 1 ORG $341
009B: 2 LOWTR EQU $9B
00B8: 3 TXTPTR EQU $B8
DEBE: 4 CHKCOM EQU $DEBE
DD7B: 5 FRMEVL EQU $DD7B
E752: 6 GETADR EQU $DD7B
FF4A: 7 IOSAVE EQU $FF4A
FF3F: 8 IOREST EQU $FF3F
D56C: 9 CRUNCH EQU $D56C
D61A: 10 FNDLIN EQU $D61A
D412: 11 ERROR EQU $D41A
0341: 12 ;
0341: 13 ; SAVE REGISTERS
0341: 14 ;
0341: 20 4A FF 15 JSR IOSAVE
0344: 16 ;
0344: 17 ; GET THE LINE NUMBER
0344: 20 BE DE 19 JSR CHKCOM
0347: 20 7B DD 20 JSR FRMEVL
034A: 20 52 E7 21 JSR GETADR
034D: 22 ;
034D; 23 ; SAVE TEXT POINTER
TEMPORARILY
034D: 24 ;
034D:A5 B8 25 LDA TXTPTR
034F:8D 9A 03 26 STA TEMPTXT
0352:A5 B9 27 LDA TXTPTR + 1
0354:8D 9B 03 28 STA TEMPTXT + 1
0357: 29 ;
0357: 30 ; TOKENIZE THE INPUT
BUFFER
0357: 31 ;
0357: A9 00 32 LDA #$00
0359: 85 B8 33 STA TXTPTR
035B: A9 02 34 LDA #$2
035D: 85 B9 35 STA TXTPTR + 1
035F: A2 FF 36 LDX #$FF
0361: A0 04 37 LDY #$4
0363: 20 6C D5 38 JSR CRUNCH
0366: 39 ;
0366: 40 ; FIND THE LINE IN THE
BASIC PROGRAM
0366: 41 ;
0366: 20 1A D6 42 JSR FNDLIN
0366: 90 2A 43 BCC NOPE
036B: 44 ;
036B: 45 ; CHANGE IT TO THE NEW
LINE STORED IN THE
INPUT BUFFER
036B: 46 ;
036B: A0 04 47 LDY #$04
036D: B9 FC 01 48 BEGIN LDA $1FC,Y
0370: F0 09 49 BEQ DONE
0372: 91 9B 50 STA (LOWTR),Y
0374: C8 51 INY
0375: D0 F6 52 BNE BEGIN
0377: A2 B0 53 LDX #$B0
0379: D0 1C 54 BNE ERR
037B: 55 ;
037B: 56 ; FILL UP THE LINE WITH COLONS
037B: 57 ;
037B: A2 3A 58 DONE LDX #$3A
037D: B1 9B 59 START LDA (LOWRE), Y
037F: F0 06 60 BEQ LAST
0381: 8A 61 TXA
0382: 91 9B 62 STA (LOWTR),Y
0384: C8 63 INY
0385: D0 F6 64 BNE START
0387: 65 ;
0387: 66 ; RESTORE TEXT POINTER
0387: 67 ;
0387: AD 9A 03 68 LAST LDA TEMPTXT
038A: 85 B8 69 STA TXTPTR
038C: AD 9B 03 70 LDA TEMPTXT + 1
038F: 85 B9 71 STA TXTPTR + 1
0391: 72 ;
0391: 73 ; RESTORE REGISTERS
0391: 74 ;
0391:20 3F FF 75 JSR IOREST
0394:60 76 RTS
0395:A2 5A 77 NOPE LDX #$5A
0397:4C 12 D4 78 ERR JMP ERROR
039A: 79 TEMPTXT DS $2
Program 2.
SOURCE FILE: CHANGE - PET ---- NEXT OBJECT FILE NAME IS CHANGE - PET. OBJO 033A: 1 ORG $33A 005C: 2 LOWTR EQU $5C 0077: 3 TXTPTR EQU $77 BEF5: 4 CHKCOM EQU $BEF5 BD98: 5 FRMEVL EQU $BD98 C92D: 6 GETADR EQU $C92D B4FB: 7 CRUNCH EQU $B4FB B5A3: 8 FNDLIN EQU $B5A3 B3CF: 9 ERROR EQU $B3CF 033A: 10 ; 03AA: 11 ; SAVE REGISTERS 033A: 12 ; 033A: 48 13 PHA 033B: 08 14 PHB 033C: 8A 15 TXA 033D: 48 16 PHA 033E: 98 17 TYA 033F: 48 18 PHA 0340: 19 ; 0340: 20 ; GET THE LINE NUMBER 0340: 21 ; 0340: 20 F5 BE 22 JSR CHKCOM 0343: 20 98 BD 23 JSR FRMEVL 0346: 20 2D C9 24 JSR GETADR 0349: 25 ; 0349: 26 ; SAVE TEXT POINTER TEMPORARILY 0349: 27 ; 0349: A5 77 28 LDA TXTPTR 034B: 8D 99 03 29 STA TEMPTXT 034E: A5 78 30 LDA TXTPTR + 1 0350: 8D 9A 03 31 STA TEMPTXT + 1 0353: 32 ; 0353: 33 ; TOKENIZE THE INPUT BUFFER 0353: 34 ; 0353: A9 00 35 LDA #$00 0355: 85 77 36 STA TXTPTR 0357: A9 02 37 LDA #$2 0359: 85 78 38 STA TXTPTR + 1 035B: A2 FF 39 LDX #$FF 035D: A0 04 40 LDY #$4 035F: 20 FB B4 41 JSR CRUNCH 0362: 42 ; 0362: 43 ; FIND THE LINE IN THE BASIC PROGRAM 0362: 20 A3 BG 45 JSR FNDLIN 0365: 90 2D 46 BCC NOPE 0367: 47 ; 0367: 48 ; CHANGE IT TO THE NEW LINE STORED IN THE INPUT BUFFER 0367: 49 ; 0367: A0 04 50 LDY #$04 0369: B9 FC 01 51 BEGIN LDA $1FC, Y 036C: F0 09 52 BEQ DONE 036E: 91 5C 53 STA (LOWTR), Y 0370: C8 54 INY 0371: D0 F6 55 BNE BEGIN 0373: A2 B0 56 LDX #$B0 0375: D0 1F 57 BNE ERR 0377: 58 ; 0377: 59 ; FILL UP THE LINE WITH COLONS 0377: 60 ; 0377: A2 3A 61 DONE LDX #$3A 0379: B1 5C 62 START LDA (LOWTR), Y 037B: F0 06 63 BEQ LAST 037D: 8A 64 TXA 037E: 91 5C 65 STA (LOWTR), Y 0380: C8 66 INY 0381: D0 F6 67 BNE START 0383: 68 ; 0383: 69 ; RESTORE TEXT POINTER 0383: 70 ; 0383: AD 99 03 71 LAST LDA TEMPTXT 0386: 85 77 72 STA TXTPTR 0388: AD 9A 03 73 LDA TEMPTXT + 1 038B: 85 78 74 STA TXTPTR + 1 038D: 75 ; 038D: 76 ; RESTORE REGISTERS 038D: 77 ; 038D: 68 78 PLA 038E: A8 79 TAY 038F: 68 80 PLA 0390: AA 81 TAX 0391: 28 82 PLP 0392: 68 83 PLA 0393: 60 84 RTS 0394: A2 5A 85 NOPE LDX #$5A 0396: 4C CF B3 86 ERR JMP ERROR 0399: 87 TEMPTXT DS $2
Program 3.
" : 033A 48 08 8A 48 98 48 20 F5 " : 0342 BE 20 98 BD 20 2D C9 A5 " : 034A 77 8D 99 03 A5 78 8D 9A " : 0352 03 A9 00 85 77 A9 02 85 " : 035A 78 A2 FF A0 04 20 FB B4 " : 0362 20 A3 B5 90 2D A0 04 B9 " : 036A FC 01 F0 09 91 5C C8 D0 " : 0372 F6 A2 B0 D0 1F A2 3A B1 " : 037A 5C F0 06 8A 91 5C C8 D0 " : 0382 F6 AD 99 03 85 77 AD 9A " : 038A 03 85 78 68 A8 68 AA 28 " : 0392 68 60 A2 5A 4C CF B3 EF
Program 4.
10 INPUT" {CLEAR} CHANGE TO"; IN$
20 CHANGE = 826: LINE = 100
30 SYSCHANGE, LINE
40 PRINT" {CLEAR} IN$ EQUALS :" IN$ : LIST
100 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Program 5.
10 PRINT" {CLEAR} CHANGE TO "; : GOSUB 1000
20 CHANGE = 826 : LINE = 100
30 SYSCHANGE, LINE
40 PRINT" {CLEAR} IN$ EQUALS : "IN$: LIST
100 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::
1000 SYS48117
1010 FOR B = 512 TO 592 : IF PEEK (b) <> 0 THEN NEXT
1020 IN$ = "" : POKE PEEK (68) + 256 * PEEK (69) + 1, 0 : [POKE PEEK (68) + 256 * PEEK (69) + 2, 2
1030 POKE PEEK (68) + 256* PEEK (69), B - 512 : IN$ = MID$ (IN$,1) : RETURN