THE OSI® GAZETTE
A 6502 Disassembler
Thomas G. Gordon
As the proud owner of an OSI Superboard II, I was immediately curious to see what made it tick. A little peeking into the Basic-in-Roms via the monitor was enough to convince me that I needed a good disassembler if I was going to get anywhere. Listing 1 is the resultant 6502 disassembler. Although written in Microsoft Basic to run on my OSI, it should run on any 6502 based system with minor modifications (8K memory needed).
Although I feel the program is fairly straight-forward, a few words may be in order to explain its operation.
Lines 5 - 30 print a greeting and ask for a starting address at which to begin disassembling.
The subroutines at 900-990 and 1000-1095 are hex to decimal and decimal to hex conversion routines, respecitvely.
the subroutine at lines 250-340 inserts the mnemonic op codes into the array R$, dimensioned by line 5. Each mnemonic contains a fourth letter which I call a tag code. The purpose of the tag code is to identify the addressing mode associated with that particular op code. For example, the tag R indicates relative more addressing.
Lines 40-75 fetch the numerical opcode, print the current address in hex, determine if it is a legal op code, (if not, the operator is requested to enter another starting address) and print the hex op code along with its three letter mnemonic.
Lines 85-150 determine the addressing mode by examining the tag code, and jump to the proper routine to print any associated arguments (data or address) following the op code. These routines are located at lines 600-795.
The disassembler will continue to run until killed by the operator or an invalid op code is found.
LISTING 1 5 DIMR$ (257) 10 PRINT "6502 DISASSEMBLER" : PRINT : PRINT 15 GOSUB250 20 PRINT "ENTER START ADDRESS" 25 PRINT "IN HEX, USE 4 DIGITS." 30 INPUTA$ 35 GOSUB900 40 Z = PEEK(S) : A = S 55 GOSUB1000 : REM-GET HX ADR 60 PRINTER$ : TH$ : TW$ : OE$; " "; 65 IFR$(Z) = "" THENPRINT "INVALID CODE" : GOTO20 70 A = Z : GOSUB1000 75 PRINTTW$; OE$; " "; LEFT$(R$(Z), 3); " "; 85 U$ = RIGHT$ (R$(Z), 1) 90 IFU$ = " " THENPRINTU$:S = S + 1 : GOTO40 95 IFU$ = "N" THENPRINT "A*"; : GOTO600 100 IFU$ = "A" THENPRINTU$ : S = S+1 : GOTO40 105 IFU$ = "Z" THENPRINT "A*"; : GOTO625 110 IFU$ = "*" THENPRINT "*$"; : GOTO625 115 IFU$ = "X" THENPRINT "A*"; : GOTO645 120 IFU$ = "Y" THENPRINT "A*"; : GOTO665 125 IFU$ = "B" THENPRINT " ("; : GOTO685 130 IFU$ = "C" THENPRINT " ("; : GOTO700 135 IFU$ = "U" THENPRINT "A*"; : GOTO715 140 IFU$ = "R" THENPRINT "TO"; : GOTO765 145 IFU$ = "J" THENPRINT " ("; : GOTO735 150 IFU$ = "V" THENPRINT "A*"; : GOTO755 250 FORX = 0TO255 : READM$ : R$(X) = M$ : NEXT 255 DATABRK , ORAB, , , ,ORAZ, ASLZ,, PHP , ORA*, ASLA,,, ORAN 260 DATAASLN,, RPLR, ORAC,,,, DRAU, ASLU,,CLC , ORAY,,,, DRAX 265 DATAASLX,, JSRN, ANDB,,, BITZ,ANDZ,ROLZ,,PLP ,AND*, ROLA,, BITN 270 DATAANDU,ROLN,, BMIR,ANDC,,,,ANDU,ROLU,,SEC , ANDY,,, 275 DATAANDX, ROLX,,RTI ,EORB,,,, EORZ,LSRZ,, PHA , EDR*, LSRA,, JMPN 280 DATAEORN, LSRN,, BVCR, EORC,,,, EORU, LSRU,, CLI, EORY,,, 285 DATAFORX, LSRX,, RTS , ADCB,,,, ADCZ,RORZ,,PLA , ADC*, RORA,, JMP J 290 DATAADCN,RORN,,BVSR,ADCC,,,,ADCU,RORU,,SEI ,ADCY,,,, ADCX,,, 295 DATASTAB,,, STYZ, STAZ, STXZ,, DEY ,, TXA ,, STYN, STAN, STXN,, BCCR 300 DATASTAC,,, STYU,STAU,STXV,, TYA , STAY,TXS ,,, STAX,,,LDY* 305 DATALDAB, LDX*,, LDYZ, LDAZ, LDXZ,, TAY , LDA*, TAX ,, LDYN, LDAN, LDXN 310 DATA,BCSR, LDAC,,,LDYU, LDAU, LDXV,, CLV , LDAY, TSX ,, LDYX,LDAX 315 DATALDXY,, CPY*, CMPB,,, CPYZ, CMPZ, DECZ,, INY , CMP*, DEX , 320 DATACPYN, CMPN, DECN,, BNER, CMPC,,,, CMPU, DECU,, CLD , CMPY,,, 325 DATACMPX, DECX,, CPX*, SBCB,,, CPXZ, SBCZ,INCZ,, INX ,SBC*, NOP , 330 DATACPXN, SBCN,INCN,, BEQR, SBCC,,, 335 DATASBCU, INCU,, SED , SBCY,,,,SBCX, INCX, 340 RETURN 600 A = PEEK (S+2) : GOSUB1000 605 PRINTTW$; OE$; 610 A = PEEK (S+1) : GOSUB1000 615 PRINTTW$; OE$ 620 S = S + 3 : GOTO40 625 A = PEEK (S+1) : GOSUB1000 630 PRINTTW$; OE$ 632 S = S+2 : GOTO40 645 A = PEEK (S+2) : GOSUB1000 650 PRINTTW$; OE$; 655 A = PEEK (S+1) : GOSUB1000 660 PRINTTW$; OE$; ,X:S = S +3 : GOTO40 665 A = PEEK (S+2) : GOSUB1000 670 PRINTTW$; OE$; 675 A = PEEK (S+1) : GOSUB1000 680 PRINTTW$: OE$; " , Y" : S = S+3: GOTO40
The format of the resultant printout pretty much follows standard assembler notation, with one exception. When relative addressing mode is encountered, the program prints the hex address to which the branch occurs, rather than the hex offset. I found this to be much more convenient when disassembling. Since it is a one pass only disassembler, the use of labels was out, but this works just as well in my opinion.
Finally, listing 2 shows the resultant printout of some of the OSI code beginning at hex FD00, which is the start of the keyboard monitor routine.
685 A=PEEK (S+1): GOSUB 1000 690 PRINT TW$;OE$; ", X> ": GOTO632 700 A=PEEK (S+1): GOSUB1000 705 PRINTTW$;OE$;">, Y": GOTO632 715 A=PEEK (S+1): GOSUB1000 720 PRINTTW$; OE$;" ,X": GOTO632 735 A=PEEK (S+2): GOSUB1000 740 PRINTTW$; OE$; 745 A=PEEK (S+1): GOSUB1000 750 PRINTTW$; OES;">": S=S+3:GOTO40 755 A=PEEK (S+1): GOSUB1000 760 PRINTTW$;OE$; "Y": GOTO632 765 A=PEEK (S+1) : IFA <128THEN790 770 A=255-A 775 A=S+1-A: GOSUB 1000 780 PRINTFR$;TH$; TW$; OE$: GOTO632 790 A=S+A+2:GOSUB1000 795 GOTO780 900 B$=LEFT$(A$,1): C$=MID$ (A$, 2, 1): D$=MID$(A$,3,1) 915 E$=MID$ (A$,4,1): F$=B$ 925 FORX=1TO4 930 IFF$="A" THENA=10:GOTO965 935 IFF$="B" THENA=11:GOTO965 940 IFF$="C" THENA=12:GOTO965 945 IFF$="D" THENA=13:GOTO965 950 IFF$="E" THENA=14:GOTO965 955 IFF$="F" THENA=15:GOTO965 960 A=VAL (F$) 965 IFX=1 THENS=A+4096:F$=C$ 970 IFX=2 THENS=S+A+256:F$=D$ 975 IFX=3 THENS=S+A+16:F$=E$ 980 IFX=4THENS=S+A 985 NEXTX 990 RETURN 1000 F=INT (A/4096): REM-D TO H CONVERT 1005 R=A-F+4096 1010 TH=INT (R/256) A last minute correction from the 1015 R=R-TH+256 author: Line 1065 works as is for 1020 TW=INT (R/16) APPLE; for OSI it should read 1065 1025 OE=R-TW+16:H=F F$ = MID$ (STR$(H),2) 1030 FORX=1TO4 1035 IFH=10THENF$= "A": GOTO1070 1040 IFH=11THENF$= "B": GOTO1070 1045 IFH=12THENF$= "C": GOTO1070 1050 IFH=13THENF$= "D": GOTO1070 1055 IFH=14THENF$= "E": GOTO1070 1060 IFH=15THENF$= "F": GOTO1070 1065 F$=STR$ (H) 1070 IFX=1THENFR$=F$:H=TH 1075 IFX=2THENTH$=F$:H=TW 1080 IFX=3THENTW$=F$:H=OE 1085 IFX=4THENOE$=F$ 1090 NEXTX 1095 RETURN
LISTING 2 RUN 6502 DISASSEMBLER FNTER START ADDRESS IN HEX, USF 4 DIGITS, ? FD00 FD00 8A TXA FD01 48 PHA FD02 98 TYA FD03 48 PHA FD04 A9 LDA *$01 FD06 20 JSR A*FCBE FD09 20 JSR A*FCC6 FD0C D0 BNE TO FD13 FD0E OA ASL A FD0F D0 BNE TO FD06 FD11 F0 BEQ TO FE66 FD13 4A LSR A FD14 90 BCC TO FD1F FD16 2A ROL A FD17 E0 CPX *$21 FD19 D0 BNE TO FD0E FD1B A9 LDA *$1B FD1D D0 BNE TO FD40 FD1F 20 JSR A*FDC8 FD22 98 TYA FD23 8D STA A*0213 FD26 0A ASL A FD27 0A ASL A