Apple Machine Language Memory Aid
K. Lourash, Decatur, IL
"ML Helper" is a utility developed to assist fledgling Apple machine language programmers in studying 6502 object code when the original source code is not available, and also in adapting that code to their particular needs and systems. This program also works as is on OS1 and can easily be modified for any Microsoft BASIC.
Options are offered in this program to list and modify zero page usage, to list and modify absolute addressing references, and to relocate the code under examination. Although written in Microsoft floating-point BASIC, this utility is readily converted to the other popular dialects. In fact, while my system is OSI, the listing is for Apple simply to involve a wider audience.
You may save ML Helper without REMarks. If you do, notice that line 31 may be incorporated into line 29, and line 35 into line 33, for increased program optimization. However, do not tamper with the "NEXT A" statement of line 51, since ML Helper will exit a loop without completing it; a simple "NEXT" there is insufficient.
In the interest of brevity, I chose to do no error checking of input from the keyboard. Thus it's easy to become careless and obtain seemingly inexplicable program performance. Also, when using hexadecimal notation, I assumed you won't prefix an address with the "$" symbol. Furthermore, leading zeros are harmless, but quite unnecessary. No relocate is foolproof. Hence, ML Helper does not resolve the indirect JMP or the technique of jumping with an RTS once the stack has been prepared. In other words, jump tables and data blocks are moved unchanged.
Disassemble And Relocate
When up and running, ML Helper emulates a disassembler, examining the address range you've specified for valid 6502 operation codes. When they are found, the program logic proceeds to list or modify the zero page references, to list external absolute references, to modify absolute references, or to move code and modify addresses for a successful relocate, whichever option is operative.
Bytes determined to be invalid instruction code sequences are assumed to form data tables. A data table finder, as such, is always active and can actually become an unspecified sixth option to locate unknown data table areas.
At this point I set an arbitrary criterion — namely, that wherever there occurs a block of six or fewer consecutive bytes of executable code, the data table finder should, nonetheless, report that block of code as part of a data table area. If this standard proves unsuitable for your requirements, then change the "A-7" expression in line 350. The absence of data tables is reported as an address range of 0-0 ($0000-0000 hexadecimal).
Menu item 4 may not be immediately clear. The "EXTERNAL" references that ML Helper will list are those absolute addresses referencing memory outside the body of the program module being examined. Displaying all absolute addressing usage produces a counterproductive volume of screen clutter which I thought best to avoid.
Menu item 5, by which you elect to change absolute references, is not similarly restricted. If during a run it appears that interesting data might scroll away, then Apple users are reminded to invoke the CTRL S Stop-List feature of their system; others may have to rely on CTRL C or divert all output to hard copy. Have fun exploring uncharted machine language programs with ML Helper pointing the way.
0 DATA 232, 200, 202, 136, 72, 104, 24, 56, 96, 170, 168, 138, 152, 234, 10, 74, 42, 106, 186 1 DATA 154, 64, 120, 88, 184, 248, 216, 8, 40, 0, 208, 240, 144, 176, 48, 16, 80, 112, 169, 162 2 DATA 160, 201, 224, 192, 105, 233, 41, 9, 73, 165, 166, 164, 133, 134, 132, 230, 198, 197, 228 3 DATA 196, 101, 229, 36, 37, 5 10 DATA 69, 38, 102, 6, 70, 181, 182, 180, 149, 150, 148, 246, 214, 213, 117 11 DATA 245, 53, 21, 85, 54, 118, 22, 86, 177, 145, 209, 113, 241, 49, 17, 81, 161, 129, 193, 97 12 DATA 225, 33, 1, 65, 32, 76, 108, 44, 173, 174, 172, 141, 142, 140, 238, 206, 205, 236, 204 13 DATA 109, 237, 45, 13, 77, 46, 110, 14, 78, 189, 190 20 DATA 188, 157, 254, 222, 221, 125, 253, 61, 29, 93, 62, 126, 30, 94, 185, 153, 217, 121, 249 21 DATA 57, 25, 89 : GOTO 530 30 REM *** LIST ADDRESSES *** 40 IF A(Z) > = S THEN IF A(Z) < = E THEN ~ RETURN 50 IF Z = 0 GOTO 80 60 FOR X = 0 TO Z - 1 : IF A(X) = A(Z) THEN RETURN 68 S(T) = VAL (H$) : E(T) = VAL (E$) 70 NEXT 80 PRINT "ADDR REF'D : "; : IF H THEN D = A(Z) : GOSUB 220 : PRINT "$"H$ : GOTO 100 90 PRINT A(Z)100 Z = Z + 1 - (Z > 29) : RETURN 110 REM *** ZERO PAGE CHANGE *** 120 FOR I = 0 TO X : IF C(I) = A(Z) THEN POKE A + 1, D(I) 130 NEXT : RETURN 140 REM *** RELOCATE *** 150 IF A(Z) < TS OR A(Z) > TE THEN RETURN 160 I = PEEK (A + 1) + T3 : IF I > 255 THEN I ~ = I - N : T4 = T4 + 1 170 POKE A + 1, I : POKE A + 2, PEEK (A + 2) + T4 : RETURN 180 REM *** CHANGE ABSOLUTE ADDR *** 190 FOR I = 0 TO X : IF C(I) = A(Z) THEN K = INT (D(I) / N) 195 POKE A + 1, D(I) - N * K : POKE A + 2, K 200 NEXT : RETURN 210 REM *** DEC - HEX *** 220 H$ = "" : F = 4096 : FOR J = H TO 4 : K = INT ~ (D / F) : D = D - K * F 225 H$ = H$ + MID$ (G$, K + H, H) : F = F / 16 : NEXT : RETURN 230 REM *** DEC - HEX *** 240 D = 0 : F = H : FOR J = LEN (H$) TO H STEP - ~ H : M = ASC ( MID$ (H$, J, H )) - 48 245 D = D + F * (M - 7 * (M > 9) ) : F = 16 * F : ~ NEXT : RETURN 250 REM *** PRINT DATA TABLES *** 260 PRINT "DATA TABLE : " ; : IF H THEN D = T1 : ~ GOSUB 220 : PRINT "$" H$ "-" ; : D = T2 265 GOSUB 220 : PRINT H$ : RETURN 270 PRINT T1"-" T2 : RETURN 280 REM *** MAIN ROUTINE *** 290 FOR A = S TO E 300 REM *** SKIP DATA TABLES *** 310 FOR I = 0 TO T : IF S(I) THEN IF A > = S(I) THEN A = E(I) + 1 : S(I) = 0 320 NEXT : FOR I = 0 TO 150 : READ M : IF PEEK (A) = M GOTO 390 330 NEXT 340 REM *** PRINT DATA TABLES *** 350 IF A - 7 > T2 THEN IF T1 THEN GOSUB 260 : T1 = A 360 IF T1 = 0 THEN T1 = A 370 T2 = A : GOTO 510 380 REM *** 1 - BYTE IGNORE *** 390 IF I < 29 GOTO 510 400 REM *** 2-BYTE IGNORE *** 410 IF I < 48 GOTO 500 420 REM *** ZERO PAGE *** 430 IF I > 102 OR C > 2 GOTO 470 440 IF C < 3 THEN A(Z) = PEEK (A + 1) : ON C GOSUB 50, 120 450 GOTO 500 460 REM *** 3 - BYTE *** 470 IF I < 103 GOTO 500 480 IF C > 2 THEN A(Z) = PEEK (A + 1) + PEEK (A ~ + 2) * N : ON C - 2 GOSUB 150, 40, 190 490 A = A + 1 500 A = A + 1 510 RESTORE : NEXT A : GOSUB 260 : END 520 REM *** END OF MAIN ROUTINE *** 530 PRINT "1 = LIST ZERO PAGE REFERENCES" : PRINT "2 = CHANGE ZERO PAGE REFERENCES" 531 PRINT "3 = RELOCATE" : PRINT "4 = LIST EXTERNAL ABSOLUTE REFERENCES" 532 PRINT "5 = CHANGE ABSOLUTE REFERENCES" : PRINT : PRINT "CHOOSE ONE: " ; : GET H$ 533 PRINT H$ : C = VAL (H$) : PRINT : PRINT "WANT HEX NUMBERS, Y/N? " ; : GET H$ : PRINT H$ 540 PRINT : H = H$ = "Y" : N = 256 : G$ = "0123456789ABCDEF": DIM A(30) 541 INPUT "INPUT START, END ADDRESSES : " ; H$, E$ : PRINT 542 IF H THEN GOSUB 240 : S = D : H$ = E$ : GOSUB 240 : E = D : GOTO 560 550 S = VAL (H$) : E = VAL (E$) 560 IF C < > 3 GOTO 660 570 INPUT "INPUT TARGET ADDRESS : " ; H$ : PRINT : IF H THEN GOSUB 240 : TS = D : GOTO600 580 TS = VAL (H$) 590 REM *** CALCULATE OFFSET *** 600 TE = TS + E - S : I = ABS (TS - S) : T4 = INT ~ (I / N) : T3 = I - T4 * N 605 IF TS < S THEN T3 = - T3 : T4 = - T4 610 REM *** MOVE ROUTINE *** 620 IF T3 > 0 THEN K = TE : FOR I = E TO S STEP - 1 : POKE K, PEEK (I) : K = K - 1 625 NEXT : GOTO 650 630 K = TS : FOR I = S TO E : POKE K, PEEK (I) : ~ K = K + 1 : NEXT 640 REM *** SWAP TS & S, TE & E *** 650 K = TS : TS = S : S = K : K = TE : TE = E : E = K 660 PRINT "LIST UP TO 11 KNOWN DATA TABLES IN ~ THE PROGRAM. TYPE 0, 0 WHEN DONE." : PRINT 670 PRINT "DATA TABLE "T" START, END : " ; : INPUT "" ; H$, E$ 675 IF H THEN GOSUB 240 : S(T) = D : H$ = E$ : GOSUB 240 : E(T) = D : GOTO 690 680 S(T) = VAL (H$) : E(T) = VAL (E$) 690 IF E(T) THEN I = T3 + T4 * N : S(T) = S(T) + I : E(T) = E(T) + I : T = T + 1 695 IF T < 11 GOTO 670 700 IF C < > 2 THEN IF C < > 5 THEN PRINT : GOTO 290 710 PRINT : PRINT "LIST UP TO 11 ADDRESSES TO BE CHANGED. TYPE 0, 0 WHEN DONE. " : PRINT 720 PRINT "#"X". OLD, NEW ADDRESSES : " ; : INPUT "" ; H$, E$ 725 IF H THEN GOSUB 240 : C(X) = D : H$ = E$ : GOSUB 240 : D(X) = D : GOTO 740 730 C(X) = VAL (H$) : D(X) = VAL (E$) 740 IF C(X) = D(X) OR X = 10 THEN PRINT : GOTO 290 750 X = X + 1 : GOTO 720