/* ---------------------------------------------------------------------- */ /* Copyright (C) 1992 by Natrlich! */ /* This file is copyrighted! */ /* Refer to the documentation for details. */ /* ---------------------------------------------------------------------- */ /* rev. history 1.0 -- original buggy version */ /* 1.1 -- fixed bcc/bpl bug */ /* 1.2 -- fixed dget_j, added ASCII support */ /* 1.3 -- fixed tables (at LEAST 6 Errors) */ /* 1.4 -- X drivers, .O65, FF FF done rite, */ /* Boot files */ /* 1.5 -- print inverted chars optionally */ /* 1.6 -- even more boot file support */ /* 1.7 -- AppleII and C64 support */ /* 1.8 -- no real changes, actually */ /* ---------------------------------------------------------- */ #include "defines.h" #include #include #include #include #define __BIG_GENERATOR__ #include OSBIND #include "code.h" #include "seg.h" #include "object.h" #define ATARI 0 #define PLAIN 1 #define C64 2 #define APPLE 3 #define SPARTA 4 #define MODULE 5 #define BOOT 6 #define CHMIN ' ' #define CHMAX '~' #ifdef isprint # undef isprint #endif #define toprint( c) ((c) & (0x7F | inverted)) #define isprint( c) ( toprint( c) >= CHMIN && toprint( c) <= CHMAX) #define chprint( c) ( isprint( c) ? (char) toprint( c) : '.') word disasm(), seg_disasm(); extern char trc_loss[]; int maxerrors = 100; struct { byte flag, secs; word start, init; } boot_header; struct { word ffff, start, end; } ffff_header; struct { byte byte1, byte2; word start, len; } feff_header; struct { byte byte1, len_lsb, len_msb; } fdff_header; struct { byte mode, lsb, msb; char id[ 8]; } fcff_header; struct { char id[8]; word w1; } fbff_header; struct { word start, end; } faff_header; struct { word start, end; } apple_header; struct { word start, end; } c64_header; word __x; lword __lx; void fixheader() { ffff_header.start = dpeek( &ffff_header.start); ffff_header.end = dpeek( &ffff_header.end); } #if OS == TOS int tossable; #endif char cminusminus[] = "; ---------------------------------------\n"; FILE *fq; int pcoff, showascii = 1, showheader, pstart, inverted, filetype; lword space, mspace; byte *room; long bread; int fp; int tok_remain; main( argc, argv) int argc; char **argv; { static char infile[ 256], outfile[ 256]; int i = 0; fq = stdout; /* done here for some lame Amiga cc */ #if ! VERSION chk_tables(); #endif while( ++i < argc) { if( *argv[i] == '-') switch( Xtolower( argv[i][1])) { #if OS == TOS case 't' : tossable = ! tossable; break; #endif case 'f' : switch( Xtolower( argv[ i][2])) { case 'o' : filetype = MODULE; break; case 's' : filetype = SPARTA; break; case 'p' : filetype = PLAIN; if( ! sscanf( &argv[ i][ 3], "%X", &pstart) || ! pstart) nferror("Missing start address"); break; case 'b' : filetype = BOOT; break; case 'a' : filetype = APPLE; break; case 'c' : filetype = C64; break; case 0 : case 'x' : filetype = ATARI; default : goto usage; } break; case 'a' : showascii = ! showascii; break; #ifdef __DATE__ case ':' : fputs( __DATE__, stderr); # ifdef __TIME__ fprintf( stderr, " %s", __TIME__); # endif putc( '\n', stderr); break; #endif case 'v' : fprintf( stderr, "disasm65 v1.8 (c) 1992 by Natuerlich!\ -- disassembles 6502 binaries\n"); break; case 'i' : inverted = ~inverted; break; case 'h' : showheader = ! showheader; break; case 'p' : pcoff = ! pcoff; break; } else if( ! infile[0]) strcpy( infile, argv[i]); else if( ! outfile[0]) strcpy( outfile, argv[i]); else goto usage; } if( ! infile[0]) goto usage; #if OS == MSDOS _fmode = O_BINARY; #endif if( (fp = (int) Fopen( infile, OPEN_R)) < 0) nferror("File open failed"); if( outfile[0] && ! (fq = fopen( outfile, "w"))) nferror("File creation failed"); switch( filetype) { case APPLE : if( (bread = Fread( fp, 4L, &apple_header)) < 4L) nferror( trc_loss); seg_disasm( dpeek( &apple_header.start), dpeek( &apple_header.end), 0); break; case C64 : { word pos; if( (bread = Fread( fp, 2L, &c64_header)) < 2L) nferror( trc_loss); pos = Fseek( 0L, fp, SEEK_END) - 2; Fseek( 2L, fp, SEEK_SET); seg_disasm( dpeek( &c64_header), pos, 0); } break; case PLAIN : { word pos; pos = (word) Fseek( 0L, fp, SEEK_END); Fseek( 0L, fp, SEEK_SET); seg_disasm( pstart, pos, 0); } break; case BOOT : { word start; if( (bread = Fread( fp, 6L, &boot_header)) < 6L) nferror( trc_loss); start = dpeek( &boot_header.start); if( showheader) { fputs( cminusminus, fq); fprintf( fq, "; Boot header - Flag $%02X %d sectors\n\ ; Address : $%04X Init: $%04X\n", boot_header.flag, (word) boot_header.secs, start, dpeek( &boot_header.init)); fputs( cminusminus, fq); } if( ! showascii && pcoff) fprintf( fq, "; link with -x%04X\n\n", dpeek( &boot_header.init)); seg_disasm( start + 6, boot_header.secs * 0x80 - 6, 0); } break; case SPARTA : if( do_sparta()) do_atari(); break; case MODULE : do_module(); break; case ATARI : if( (bread = Fread( fp, 6L, &ffff_header)) < 6L) nferror( trc_loss); if( ffff_header.ffff != 0xFFFF) nferror("Not a $FF $FF header"); do_atari(); } #if OS == TOS keypress(); #endif return(0); usage: #if OS == TOS fputs( "usage: disasm65 [-{tpiahvf}] infile [outfile]\n", stderr); #else fputs( "usage: disasm65 [-{fahvip}] infile [outfile]\n", stderr); #endif fputs( "\ \t-p\t: turn off the dump\n\ \t-i\t: don't print inverted stuff\n\ \t-a\t: turn off ASCII dump\n\ \t-h\t: show info about the binary headers\n\ \t-v\t: version\n\ \t-f[type]: input file type (default: -fx)\n\ \t o\t: .O65 module\n\ \t a\t: Apple II ProDOS binary\n\ \t c\t: C64 binary\n\ \t pxxxx: plain 6502 binary (xxxx gives start address)\n\ \t s\t: SpartaDOS X-Cartridge drivers\n\ \t x\t: Atari 8bit FF FF binaries\n", stderr); #if OS == TOS fputs( "\t-t\t: wait for keypress before exitin'\n", stderr); keypress(); #endif return( 1); } do_atari() { lword bread; for(;;) { fixheader(); if( showheader) { fputs( cminusminus, fq); fprintf( fq, "; FFFF header start : $%04X end : $%04X\n", ffff_header.start, ffff_header.end); fputs( cminusminus, fq); } fprintf( fq, "\n\t\t * = $%04X\n\n", ffff_header.start, ffff_header.ffff); seg_disasm( ffff_header.start, (1 + ffff_header.end - ffff_header.start), 0); if( (bread = Fread( fp, 4L, ((char huge *) &ffff_header) + 2)) <= 0) break; if( bread < 4) nferror("Garbage at end of segment"); if( ffff_header.start == 0xFFFF) { ffff_header.ffff = ffff_header.start; ffff_header.start = ffff_header.end; if( (bread = Fread( fp, 2L, (char huge *) &ffff_header + 4)) <= 0 || bread < 2) nferror("It's a trashed binary"); } } } do_sparta() { word head, len, pc, byteit, oldpcoff = pcoff, oldshowascii = showascii; for(;;) { if( (bread = Fread( fp, 2L, &head)) <= 0 || (bread == 1 && head < 256)) break; if( bread != 2) nferror("File trunctated or mangled"); len = dpeek( &head); switch( len) { case 0xFFFF : ffff_header.ffff = 0xFFFF; if( (bread = Fread( fp, 4L, (char huge *) &ffff_header + 2)) != 4L) nferror( trc_loss); return( 1); case 0xFFFE : if( (bread = Fread( fp, 6L, &feff_header)) != 6L) nferror( trc_loss); len = dpeek( &feff_header.len); pc = dpeek( &feff_header.start); if( showheader) { fputs( cminusminus, fq); fprintf( fq, "; FEFF header %02X %02X start : $%04X len : $%04X\n", feff_header.byte1, feff_header.byte2, pc, len); fputs( cminusminus, fq); } fprintf( fq, "\n\t\t * = $%04X\n\n", pc); if( feff_header.byte2 > 0x80) continue; byteit = 0; break; case 0xFFFD : if( (bread = Fread( fp, 3L, &fdff_header)) != 3L) nferror( trc_loss); len = dpeek( &fdff_header.len_lsb); if( showheader) { fputs( cminusminus, fq); fprintf( fq, "; FDFF header $%02X len : $%04X\n", fdff_header.byte1, len); fputs( cminusminus, fq); } showascii = 0; pcoff = byteit = 1; break; case 0xFFFC : if( (bread = Fread( fp, 11L, &fcff_header)) != 11L) nferror( trc_loss); if( showheader) { fputs( cminusminus, fq); fputs( "; FCFF header (Export address @ loadtime)\n", fq); fputs( cminusminus, fq); } fprintf( fq, "\t\t .byte $%02X\n\t\t .word $%02X%02X\n\t\t \ .byte \"%8.8s\"\n", fcff_header.mode, fcff_header.msb, fcff_header.lsb, fcff_header.id); continue; case 0xFFFB : if( (bread = Fread( fp, 10L, &fbff_header)) != 10L) nferror( trc_loss); if( showheader) { fputs( cminusminus, fq); fputs( "; FBFF header (Import address @ loadtime)\n", fq); fputs( cminusminus, fq); } fprintf( fq, "\t\t .byte \"%8.8s\"\n\t\t .word $%04X\n", fbff_header.id, len = dpeek( &fbff_header.w1)); showascii = 0; pcoff = byteit = 1; break; case 0xFFFA : if( (bread = Fread( fp, 4L, (char huge *) &faff_header)) != 4L) nferror( trc_loss); pc = dpeek( &faff_header.start); len = dpeek( &faff_header.end); if( showheader) { fputs( cminusminus, fq); fprintf( fq, "; FAFF header start : $%04X end : $%04X\n", pc, len); fputs( cminusminus, fq); } len = 1 + len - pc; fprintf( fq, "\n\t\t * = $%04X\n\n", pc); byteit = 0; break; default : { static char mess[] = "Unknown SpartaDOS header $FFFF"; sprintf( mess + 26, "%04X", len); nferror( mess); } } pc = seg_disasm( pc, len, byteit); showascii = oldshowascii; pcoff = oldpcoff; } return( 0); } static char *txlat[] = { "Reloc. code ", "Static data ", "Reloc. .WORDs ", "Reloc. .DBYTEs", ".DS allocation" }; do_module() { extern byte huge *pb; extern s_dropped huge *ps; extern lword bytes, sbytes; word i; word pc = DEFORG; do_load( fp); if( showheader) { s_dropped huge *p = ps; word plus = 0; fputs( cminusminus, fq); fprintf( fq, "; SEGMENTS:\n"); for( i = (word) sbytes; i; i--, p++) { fprintf( fq, ";\tType: %s $%04X-$%04X\n", txlat[ p->type], DEFORG + p->index + plus, DEFORG + p->index + plus + p->size - 1); if( p->type == S_DS) plus += p->size; } fputs( cminusminus, fq); } for( i = (word) sbytes; i; i--, pc += ps->size, ps++) if( ps->type != S_DS) { disasm( pc, pb, (lword) ps->size, 0); pb += ps->size; } } word seg_disasm( pc, len, byteit) word pc, len; int byteit; { static lword space, mspace; static byte *room; space = (lword) len; if( space > mspace) { if( mspace) free( room); if( ! (room = (byte *) malloc( (mspace = space)))) nferror("out of memory"); } if( Fread( fp, space, room) != space) nferror("read failed (file truncated ?)"); return( disasm( pc, room, space, byteit)); } char adc[]="adc", xnd[]="and", asl[]="asl", bcc[]="bcc", bcs[]="bcs", beq[]="beq", bit[]="bit", bmi[]="bmi", bne[]="bne", bpl[]="bpl", bra[]="bra",xbrk[]="brk", bvc[]="bvc", bvs[]="bvs", clc[]="clc", cld[]="cld", cli[]="cli", clv[]="clv", cmp[]="cmp", cpx[]="cpx", cpy[]="cpy", dea[]="dea", dec[]="dec", dex[]="dex", dey[]="dey", eor[]="eor", ina[]="ina", inc[]="inc", inx[]="inx", iny[]="iny", jmp[]="jmp", jsr[]="jsr", lda[]="lda", ldx[]="ldx", ldy[]="ldy", lsr[]="lsr", nop[]="nop", ora[]="ora", pha[]="pha", php[]="php", phx[]="phx", phy[]="phy", pla[]="pla", plp[]="plp", plx[]="plx", ply[]="ply", rol[]="rol", ror[]="ror", rti[]="rti", rts[]="rts", sbc[]="sbc", sec[]="sec", sed[]="sed", sei[]="sei", sta[]="sta", stx[]="stx", sty[]="sty", stz[]="stz", tax[]="tax", tay[]="tay", trb[]="trb", tsb[]="tsb", tsx[]="txa", txa[]="txa", txs[]="txs", tya[]="tya", o__[]=".byte"; char *ops[] = { xbrk, ora, o__, o__, tsb, ora, asl, o__, php, ora, asl, o__, tsb, ora, asl, o__, /*0*/ bpl, ora, ora, o__, trb, ora, asl, o__, clc, ora, ina, o__, trb, ora, asl, o__, /*1*/ jsr, xnd, o__, o__, bit, xnd, rol, o__, plp, xnd, rol, o__, bit, xnd, rol, o__, /*2*/ bmi, xnd, xnd, o__, bit, xnd, rol, o__, sec, xnd, dea, o__, bit, xnd, rol, o__, /*3*/ rti, eor, o__, o__, o__, eor, lsr, o__, pha, eor, lsr, o__, jmp, eor, lsr, o__, /*4*/ bvc, eor, eor, o__, o__, eor, lsr, o__, cli, eor, phy, o__, o__, eor, lsr, o__, /*5*/ rts, adc, o__, o__, stz, adc, ror, o__, pla, adc, ror, o__, jmp, adc, ror, o__, /*6*/ bvs, adc, adc, o__, stz, adc, ror, o__, sei, adc, ply, o__, jmp, adc, ror, o__, /*7*/ bra, sta, o__, o__, sty, sta, stx, o__, dey, o__, txa, o__, sty, sta, stx, o__, /*8*/ bcc, sta, sta, o__, sty, sta, stx, o__, tya, sta, txs, o__, stz, sta, stz, o__, /*9*/ ldy, lda, ldx, o__, ldy, lda, ldx, o__, tay, lda, tax, o__, ldy, lda, ldx, o__, /*A*/ bcs, lda, lda, o__, ldy, lda, ldx, o__, clv, lda, tsx, o__, ldy, lda, ldx, o__, /*B*/ cpy, cmp, o__, o__, cpy, cmp, dec, o__, iny, cmp, dex, o__, cpy, cmp, dec, o__, /*C*/ bne, cmp, cmp, o__, o__, cmp, dec, o__, cld, cmp, phx, o__, o__, cmp, dec, o__, /*D*/ cpx, sbc, o__, o__, cpx, sbc, inc, o__, inx, sbc, nop, o__, cpx, sbc, inc, o__, /*E*/ beq, sbc, sbc, o__, o__, sbc, inc, o__, sed, sbc, plx, o__, o__, sbc, inc, o__ /*F*/ }; byte mode[]= { 8, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 1,0xF,0, 0x5, 5, 5, 0, /*0*/ 9, 0xB, 0xD, 0, 2, 3, 3, 0, 8, 7, 8, 0, 0x5, 6, 6, 0, /*1*/ 5, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 1,0xF,0, 0x5, 5, 5, 0, /*2*/ 9, 0xB, 0xD, 0, 3, 3, 3, 0, 8, 7, 8, 0, 0x6, 6, 6, 0, /*3*/ 8, 0xA, 0x0, 0, 0, 2, 2, 0, 8, 1,0xF,0, 0x5, 5, 5, 0, /*4*/ 9, 0xB, 0xD, 0, 0, 3, 3, 0, 8, 7, 8, 0, 0x0, 6, 6, 0, /*5*/ 8, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 1,0xF,0, 0xC, 5, 5, 0, /*6*/ 9, 0xB, 0xD, 0, 3, 3, 3, 0, 8, 7, 8, 0, 0xE, 6, 6, 0, /*7*/ 9, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 0, 8, 0, 0x5, 5, 5, 0, /*8*/ 9, 0xB, 0xD, 0, 3, 3, 4, 0, 8, 7, 8, 0, 0x6, 6, 6, 0, /*9*/ 1, 0xA, 0x1, 0, 2, 2, 2, 0, 8, 1, 8, 0, 0x5, 5, 5, 0, /*A*/ 9, 0xB, 0xD, 0, 3, 3, 4, 0, 8, 7, 8, 0, 0x6, 6, 7, 0, /*B*/ 1, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 1, 8, 0, 0x5, 5, 5, 0, /*C*/ 9, 0xB, 0xD, 0, 0, 3, 3, 0, 8, 7, 8, 0, 0x0, 6, 6, 0, /*D*/ 1, 0xA, 0x0, 0, 2, 2, 2, 0, 8, 1, 8, 0, 0x5, 5, 5, 0, /*E*/ 9, 0xB, 0xD, 0, 0, 3, 3, 0, 8, 7, 8, 0, 0x0, 6, 6, 0 /*F*/ }; #if ! VERSION chk_tables() { register byte huge *p = mode; register char huge **q = ops; register int i = 256; while( i--) if( (*q++ != o__) ^ (*p++ >= 1)) fprintf( stderr, "Table entry mismatch for op-code $%02X \ mnemo=\"%s\" mode=%d\n", 255 - i, q[-1], p[-1]); } #endif #define get_j() \ { \ pc++; \ if( len--) \ j = *p++; \ else \ goto fini; \ } #define dget_j() \ if( (len - 2) >= 0) \ { \ j = dpeek( p); \ and = j; \ shift= peek( p + 1); \ p += 2; \ len -= 2; \ pc += 2; \ } \ else \ goto fini2 #define printpc() fprintf( fq, "%04X ", pc) word disasm( pc, p, len, byteit) register word pc; byte huge *p; word byteit; long len; { register word i, j; register byte shift, and; while( len--) { if( ! pcoff) printpc(); else putc( '\t', fq); i = *p++; pc++; if( byteit) { if( ! pcoff) fprintf( fq, "%02X", i); fprintf( fq, "\t .byte $%02X", i); if( showascii) fprintf( fq, "\t\t; \"%c\"", chprint( i)); } else switch( mode[i]) { case 0x0 : if( ! pcoff) fprintf( fq, "%02X", i); fprintf( fq, "\t %s", ops[ i]); if( ops[i] == o__) fprintf( fq, " $%02X", i); if( showascii) fprintf( fq, "\t\t; \"%c\"", chprint( i)); break; case 0x1 : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s #", ops[i]); if( j < 0xA) fprintf( fq, "%d", j); else fprintf( fq, "$%X", j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0x2 : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s $%02X", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0x3 : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s $%02X,X", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0x4 : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s $%02X,Y", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0x5 : dget_j(); if( ! pcoff) fprintf( fq, "%02X %02X %02X", i,(word) and,(word) shift); fprintf( fq, "\t %s $%04X", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c%c\"", chprint( i), chprint( and), chprint( shift)); break; case 0x6 : dget_j(); if( ! pcoff) fprintf( fq, "%02X %02X %02X", i,(word) and,(word) shift); fprintf( fq, "\t %s $%04X,X", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c%c\"", chprint( i), chprint( and), chprint( shift)); break; case 0x7 : dget_j(); if( ! pcoff) fprintf( fq, "%02X %02X %02X", i,(word) and,(word) shift); fprintf( fq, "\t %s $%04X,Y", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c%c\"", chprint( i), chprint( and), chprint( shift)); break; case 0x8 : if( ! pcoff) fprintf( fq, "%02X", i); fprintf( fq, "\t %s", ops[i]); if( showascii) fprintf( fq, "\t\t\t; \"%c\"", chprint( i)); break; case 0x9 : { register byte j; register word k; get_j(); k = j; if( ! pcoff) fprintf( fq, "%02X %02X", i, k); fprintf( fq, "\t %s $%04X", ops[ i], pc + (signed char) j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); } break; case 0xA : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s ($%02X,X)", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0xB : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s ($%02X),Y", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0xC : dget_j(); if( ! pcoff) fprintf( fq, "%02X %02X %02X", i,(word) and,(word) shift); fprintf( fq, "\t %s ($%04X)", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c%c\"", chprint( i), chprint( and), chprint( shift)); break; case 0xD : get_j(); if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t %s ($%02X)", ops[i], j); if( showascii) fprintf( fq, "\t\t; \"%c%c\"", chprint( i), chprint( j)); break; case 0xE : dget_j(); if( ! pcoff) fprintf( fq, "%02X %02X %02X", i,(word) and,(word) shift); fprintf( fq, "\t %s ($%04X,X)", ops[i], j); if( showascii) fprintf( fq, "\t; \"%c%c%c\"", chprint( i), chprint( and), chprint( shift)); break; case 0xF : if( ! pcoff) fprintf( fq, "%02X", i); fprintf( fq, "\t %s a", ops[i]); if( showascii) fprintf( fq, "\t\t; \"%c\"", chprint( i)); break; } putc( '\n', fq); } return( pc); fini: if( ! pcoff) fprintf( fq, "%02X", i); fprintf( fq, "\t .byte $%02X", i); if( showascii) fprintf( fq, "\t\t; \"%c\"", chprint( i)); putc( '\n', fq); return( pc); fini2: if( ! len) goto fini; j = *p; if( ! pcoff) fprintf( fq, "%02X %02X", i, j); fprintf( fq, "\t .byte $%02X, $%02X", i, j); if( showascii) fprintf( fq, "\t; \"%c%c\"", chprint( i), chprint( j)); putc( '\n', fq); return( pc); } keypress() { #if OS == TOS if( tossable) { while( Bconstat( 2)) Bconin( 2); Bconin( 2); } #endif } h_print() { fputs( "disasm65: ", stderr); } finalshit() { }