Classic Computer Magazine Archive COMPUTE! ISSUE 34 / MARCH 1983 / PAGE 225

VIC Tracing Disassembler

Peter Busby

Here's a handy tool to let you look at machine language programs — those in your VIC BASIC ROM chips, programs you've typed in from COMPUTE!, or some you've written yourself. If you don't know machine language, seeing it and watching how fast it executes might tempt you to learn more about it.

This article also describes how to adapt a special cassette technique to the VIC.

What is a disassembler? It is a program which looks at the machine code in memory, RAM or ROM, and prints the hexadecimal and decimal values or, more importantly, translates the hex code into 6502 mnemonics. These abbreviated words describe what the microprocessor is doing at that point in the machine language program being disassembled.

Why use a disassembler? Suppose you have Louis Sander's article on PET tape header machine language programs (COMPUTE!, July 1981, #14), which you wish to utilize with your computer. You would use the disassembler to discover how your computer handles tape headers and SAVEs. Hardly a week passes that I do not spend some time exploring the operating system.

The addressing modes are:

# —Immediate
Z —Zero Page
-A —Accumulator
(X) —Indexed Indirect
(Y) —Indirect Indexed
Z,X Z,Y —Zero Page Indexed
,X ,Y —AbsoluteIndexed
(I) —Indirect

No mode indicated represents either Absolute Addressing or an implied or relative operation. The addresses are shown first in hexadecimal, then in decimal, notation.

When disassembling, it is often convenient to jot down the mnemonics and assign descriptive labels to the branch targets and subroutine locations. At first these will be no more than "A", "B", etc.; but, as the purpose of each part becomes clear, the names evolve to "CHRGET", "SCNKEY", etc. Those of you with printers may wish to add a subroutine to print to hard copy.

As you work through a program, you may occasionally find "ILLEGAL" opcodes or perhaps misleading ones, particularly between subroutines. You have to follow the logic of the routines so that these traps do not prevent easy decoding. There may also be bytes of data interspersed with the program.

No one minds if you look at and disassemble a routine in order to decipher its workings and access points. If you discover that the routine you need is at $E165, by all means have your program go SYS 57701 and use the routine. On the other hand, you may not distribute any portion of copyrighted material, even with the (variable) names changed, without written permission. This program is intended only to explore the workings of your computer or to verify the assembly of your own programs.

Here's how to adapt the tape header machine language program ("MLP") routine to the VIC-20. Develop your MLP according to the precepts in Louis Sander's article. Prepare to load the program whose header you are using; place its title somewhere in RAM above the program (I use $333F on), and follow it immediately with the MLP. Generally, the title would be 16 characters and blanks and the MLP up to 171 bytes. With your monitor, display the six registers starting at $00B7 and place these values:

$ 00B7 - length of MLP + 16 for the title
  00B8 - 0
  00B9 - 0
  00BA - 1
  00BB - address of first byte of title, low byte first
  00BC   (e.g., 00BB-3f;00BC-33)

Now enter .G E156. Presto! Your program title and MLP, when LOADed, will start at $033F.

The VIC Disassembler will handle more than 10 subroutine levels with two adjustments that, however, do use extra memory: at the end of Line 520 may be added:

:DIM RE(99)

or however many you desire; also place this figure inside the parentheses in Line 280:

(SR<99)

or whatever.

10 PRINT"{CLEAR} 6502 DISASSEMBLER"
20 GOSUB 520
30 PRINT : PRINTSE$"ELP  "RIGHT$(STR$(SR),2); :GOSUB70
40 GOSUB80 : FOR I = 1 TO 12 : IFA$<>MID$(SE$, I,1) THENNEXT : GOTO 40
50 PRINT" ";:GOSUB70
60 MODE$ = "   ":LI = PA : ONIGOSUB 220, 220, 200, 630, 210, 180, 580, 999, 170, 190, 220, 600 : GOTO 30
70 FOR J = 0 TO 18 : PRINTCHR$(157); : NEXT : RETURN : REM CURSOR LEFT'S - APPLE USE CHR$(8)
80 POKE 198, 0 : WAIT 198, 1 : GETA$ : RETURN : REM A PPLE USE GETA$ : ON-(A$ = "")GOTO80 : RETURN
90 J = 3 + 2*(A<LI) : K = 16
100 A% = A + HI*(A>H) : AD$ = "" : FOR I = 0 TO J : AD$ = AD$ + MID$(H$,(A%/K↑(J-I)
        AND (K-1)) + 1, 1) : NEXT : RETURN
110 AD = 0 : FOR L = 1 TO R : GOSUB 260 : A = PEEK(X) : AD = AD + A*PA↑(L-1) : GOSUB90 :
        MN$ = AD$ + LEFT $ (MN$, 2) : NEXT
120 RETURN
130 J = 10 : A = 0 : K = A : L = 5
140 GOSUB80 : IF K = 0 THEN IF A$ = "$" ORA$ = "%"THEN PRINTA$; : K = 1 :
        J = 16 : IF A$ = "%"THEN J = 2 : L = 9
150 ON-(A$ = CHR$(13)) GOTO 120 : FOR I = 1 TO J : IFA$ <> MID$(H$, I, 1)THEN NEXT : GOTO140
160 PRINTA$; : A = A*J + I-1 : K = K + 1 : ON-(K<L) GOTO 140 : RETURN
170 GOSUB290 : X = Y-3 : GOTO 220
180 R =-1 : X = Z : GOTO 220
190 Y = BR : FL = 0 : IFR = -1 THEN X = X + 2*(X>1) : GOTO 220
200 IF FLAG<4 THEN ONFLGOSUB 270, 280, 290 : Z = Y
210 X = Z : R = 0
220 Z = X : A = X : LIMIT = 0 : GOSUB 90 : LI = PA : PRINTAD$ " "; : A = PEEK(X) : IFR>-1 THEN GOSUB 300
230 IFR = -1 THEN GOSUB 90 : PRINTAD$;A;IL$; : GOTO 260
240 PRINTMN$;MO$" ";IL$; : MN$ = " "
245 IF FL = 1 THEN GOSUB 110 : LI = 0 : A = Y : GOSUB ~ 90 : LI = PA : PRINT MN$" "AD$; : GOTO 260
250 IFR THEN GOSUB 110 : PRINTBS$(R);MN$;AD;BS$ (R);
260 IL$ = "" : X = X-(X<HI-1) : RETURN
270 BRANCH = X-2 : RETURN
280 SRTN = SR-(SR<10) : RETURN
290 SR = SR + (SR>0) : Y = RE(SR) : RETURN
300 R = 0 : FL = 4 : ONAAND 3 GOTO 430, 450, 460 : ONFNA(4) GOTO 370 : MN$ = MID$ (ZE$,(AAND248)/8*3+1, 3)
310 IF(A AND 31) = 16 THEN R = 1 : Y = PEEK(X + 1) : Y = X + 2 + Y-2*(Y AND 128) : FL = 1
320 ON-((A AND 31)>0)GOTO 120 : ON FNA(128)GOTO 340 : ON FNA(32)GOTO 350
330 IL$ = "              END OF ROUTINE" : RETURN
340 ON-(A = 128)GOTO 460 : R = 1 : MO$ = " # " : RETURN
350 ON FNA(64)GOTO 360 : R = 2 : Y = FNX(0) : RE(SR) = X + 3 : FL = 2 : RETURN
360 FL = 3 : ON-(SR = 0)GOTO 330 : RETURN
370 ON FNA(128)GOTO 410 : IF(A AND 247) = 36 THENMN$ = "BIT":GOTO 420
380 ON-((A AND 223)<>76)GOTO 460 : R = 2 : FL = 0 : MN$ = "JMP" : Y = FNX(0)
390 IFA = 108 THEN MO$ = "(I)" : Y = PEEK(Y) + PEEK(Y+1)*PA
400 RETURN
410 MN$ = MID$(ZE$,(A AND 224)/8*3+1, 3) : IF(A AND 80) = 80 OR A = 156 THEN 460
420 MO$ = MID$(MD$,(A AND 28)/4*3+1, 3) : R = 1-((A AND 31) = 25)-((A AND 15)> 11) : RETURN
430 GOSUB 420
440 MN$ = MID$(OP$(A AND 3),(A AND 224)/32*3+1, 3) : ON-(A = 137)GOTO 460 : RETURN
450 ON FNA(4)GOTO 500 : ON FNA(8)GOTO 470 : MO$ = " ~# " : R = 1 : IFA = 162 THEN 440
460 R=-1 : IL$="ILLEGAL" : RETURN
470 ON FNA(16)GOTO 490 : ON FNA(128)GOTO 480 : MO$ = "-A " : GOTO 440
480 MN$ = MID$(TW$,(A AND 96)/32*3+1, 3) : RETURN
490 ON-((A AND 208)<>144)GOTO 460 : MN$ = "TSX" : ON FNA(32)GOTO 120 : MN$ = "TXS" : RETURN
500 GOSUB 430 : ON-((A AND 208)<>144)GOTO 120 : ON FNA(8)GOTO 510 : MO$ = "Z, Y" : RETURN
510 ON-(A = 158)GOTO 460 : MO$ = ",Y " : RETURN
520 H$ = "0123456789ABCDEF" : SELECT$ = " ABCDENQRU H"
530 ZERO $ = "BRKPHPBPLCLCJSRPLPBMISECRTIPHABVCCLIRTSPLABVSSEI"
540 ZE$ = ZE$ + "STYDEYBCCTYALDYTAYBCSCLVCPYINYBNECLDCPXINXBEQSED"
550 OP$(1) = "ORAANDEORADCSTALDACMPSBC" : OP$(2) = "ASLROLLSRRORSTXLDXDECINC"
560 MD$ = "(X) Z  # (Y)Z, X, Y, X " : TWO$ = "TXATAXDEXNOP" : BS$(2) = CHR$(157) : REM CURSOR LEFT
570 HI = 65536 : H = 32767 : PAGE = 256 : DEFFNX(A) = PEEK(X + 1) + PEEK(X + 2)*PA : DEFFNA(B) =
        (A AND B)/B
580 PRINT"ENTER STARTING ADDRESS (PREFIX ‘$’ FOR HEX)" : GOSUB130
590 X = A*-(A<HI) : Z = X : BR = X : RE(0) = X + 3
600 PRINT : PRINT" A-DVANCE ONE STEP  B-RANCH/GO SUBROUTINE C-ONVERT BASES
610 PRINT" D-ISASSEMBLE CODES E-XAMINE ~ADDRESSES N-EW START ADDRESS ~ Q-UIT
620 PRINT" R-ETURN SUBROUTINE U-NBRANCH/BACKSTEP UP (SUBROUTINE LEVEL)" : RETURN
630 PRINT"ENTER NUMBER (PREFIX ‘$’ = HEX, ‘%’ = BINARY)" : GOSUB 130
640 PRINT : IFA>HI-1 THEN PRINT"OUT OF RANGE"; : RETURN
650 GOSUB 90 : IF A>255 THEN PRINT "$"AD$;A; : RETURN
660 PRINT"$"AD$"   % " ; : K = 2 : J = 7 : GOSUB100 : PRINT AD$;A; : RETURN
999 END