/* 6800dasm.c - a 6800 opcode disassembler */ /* version 1.0 - from 6809dasm V1.6 */ /* Copyright © 2005 Sean Riddle */ /* Freely distributable on any medium given all copyrights are retained */ /* by the author and no charge greater than $7.00 is made for obtaining */ /* this software */ /* Please send all bug reports, update ideas and data files to: */ /* seanriddle cox net */ /* the data files must be kept compatible across systems! */ /* usage: 6800dasm [] */ /* output to stdout, so use redirection */ /* The optional data file contains 7 types of lines: */ /* o Remarks - these are lines beginning with a semi-colon (;) */ /* they are completely ignored. */ /* o 1 ORG line - gives the origin of the code; this is the starting */ /* address to be used for the disassembly. */ /* o COMMENT lines - used to add comments to the end of lines of the */ /* disassembly. */ /* o COMMENTLINE lines - provide full-line comments to be included before */ /* a given address in the disassembly. */ /* o DATA lines - mark sections as data. These sections will not be */ /* disassembled, but dumped as hex data instead. */ /* o ASCII lines - mark sections as text. These sections will not be */ /* disassembled, but printed as text instead. */ /* o WTEXT lines - interprets section as text encoded as in Joust, */ /* Bubbles, Sinistar (0x0=0,...,0xa=space,0xb=A,...,0x24=Z,...,0x32=:*/ /* See sample data files (*.dat) for examples. */ /* current limitations: */ /* o number of LABEL, DATA/ASCII, COMMENT and COMMENTLINE lines determined */ /* at compile-time - see MAXLABEL, MAXDATA, MAXCOMMENT and MAXCOMMLINE */ /* o all DATA/ASCII lines in data file must be sorted in ascending */ /* address order */ /* o ditto for COMMENT and COMMENTLINE lines */ /* o if a DATA/ASCII area is preceded by what 6800dasm thinks is code */ /* that continues into the DATA/ASCII area, the data will not be marked */ /* as such, and an error will be printed. If this is the case, mark the */ /* line before the data as data also. */ /* to do: */ /* o sort comment, ascii, data lines */ /* o look at JMP and JSR addresses- set to code unless overridden */ /* in data file */ /* o perhaps a 'scan' that creates a first-guess .dat file? */ /* generate dummy labels, mark code, find ASCII, etc. */ #include "stdafx.h" #include #include #include #include /* a few of my datatypes (from Amiga) */ #define TRUE (1==1) #define FALSE (!TRUE) typedef short BOOL; /* boolean quantity */ typedef unsigned char UBYTE; /* unsigned 8-bit quantity */ /* array sizes for labels, DATA/ASCII definitions and COMMENT/COMMENTLINE */ #define MAXLABEL 999 #define MAXDATA 999 /* both DATA and ASCII lines */ #define MAXCOMMENT 999 #define MAXCOMMLINE 999 /* output listing spacing */ #define TABOPNAME 22 #define TABOPERAND 28 #define TABCOMM 43 #define OPNAMETAB (TABOPNAME-1) #define OPERANDTAB (TABOPERAND-1) #define COMMTAB (TABCOMM-1) typedef struct { /* opcode structure */ UBYTE opcode; /* 8-bit opcode value */ UBYTE numoperands; char name[6]; /* opcode name */ UBYTE mode; /* addressing mode */ UBYTE numcycles; /* number of cycles - not used */ } opcodeinfo; /* 6800 ADDRESSING MODES */ #define INH 0 #define DIR 1 #define IND 2 #define REL 3 #define EXT 4 #define IMM 5 char modenames[9][14]={ "inherent", "direct", "indexed", "relative", "extended", "immediate", }; #define NUMOPS 197 opcodeinfo opcodes[NUMOPS]={ 1,0,"NOP",INH,2, 6,0,"TAP",INH,2, 7,0,"TPA",INH,2, 8,0,"INX",INH,3, 9,0,"DEX",INH,3, 10,0,"CLV",INH,2, 11,0,"SEV",INH,2, 12,0,"CLC",INH,2, 13,0,"SEC",INH,2, 14,0,"CLI",INH,2, 15,0,"SEI",INH,2, 16,0,"SBA",INH,2, 17,0,"CBA",INH,2, 22,0,"TAB",INH,2, 23,0,"TBA",INH,2, 25,0,"DAA",INH,2, 27,0,"ABA",INH,2, 32,1,"BRA",REL,3, 34,1,"BHI",REL,3, 35,1,"BLS",REL,3, 36,1,"BCC",REL,3, 37,1,"BCS",REL,3, 38,1,"BNE",REL,3, 39,1,"BEQ",REL,3, 40,1,"BVC",REL,3, 41,1,"BVS",REL,3, 42,1,"BPL",REL,3, 43,1,"BMI",REL,3, 44,1,"BGE",REL,3, 45,1,"BLT",REL,3, 46,1,"BGT",REL,3, 47,1,"BLE",REL,3, 48,0,"TSX",INH,3, 49,0,"INS",INH,3, 50,0,"PULA",INH,4, 51,0,"PULB",INH,4, 52,0,"DES",INH,3, 53,0,"TXS",INH,3, 54,0,"PSHA",INH,3, 55,0,"PSHB",INH,3, 57,0,"RTS",INH,5, 59,0,"RTI",INH,12, 62,0,"WAI",INH,14, 63,0,"SWI",INH,14, 64,0,"NEGA",INH,2, 67,0,"COMA",INH,2, 68,0,"LSRA",INH,2, 70,0,"RORA",INH,2, 71,0,"ASRA",INH,2, 72,0,"ASLA",INH,2, 73,0,"ROLA",INH,2, 74,0,"DECA",INH,2, 76,0,"INCA",INH,2, 77,0,"TSTA",INH,2, 79,0,"CLRA",INH,2, 80,0,"NEGB",INH,2, 83,0,"COMB",INH,2, 84,0,"LSRB",INH,2, 86,0,"RORB",INH,2, 87,0,"ASRB",INH,2, 88,0,"ASLB",INH,2, 89,0,"ROLB",INH,2, 90,0,"DECB",INH,2, 92,0,"INCB",INH,2, 93,0,"TSTB",INH,2, 95,0,"CLRB",INH,2, 96,1,"NEG",IND,6, 99,1,"COM",IND,6, 100,1,"LSR",IND,6, 102,1,"ROR",IND,6, 103,1,"ASR",IND,6, 104,1,"ASL",IND,6, 105,1,"ROL",IND,6, 106,1,"DEC",IND,6, 108,1,"INC",IND,6, 109,1,"TST",IND,6, 110,1,"JMP",IND,3, 111,1,"CLR",IND,6, 112,2,"NEG",EXT,6, 115,2,"COM",EXT,6, 116,2,"LSR",EXT,6, 118,2,"ROR",EXT,6, 119,2,"ASR",EXT,6, 120,2,"ASL",EXT,6, 121,2,"ROL",EXT,6, 122,2,"DEC",EXT,6, 124,2,"INC",EXT,6, 125,2,"TST",EXT,6, 126,2,"JMP",EXT,3, 127,2,"CLR",EXT,6, 128,1,"SUBA",IMM,2, 129,1,"CMPA",IMM,2, 130,1,"SBCA",IMM,2, 132,1,"ANDA",IMM,2, 133,1,"BITA",IMM,2, 134,1,"LDAA",IMM,2, 136,1,"EORA",IMM,2, 137,1,"ADCA",IMM,2, 138,1,"ORAA",IMM,2, 139,1,"ADDA",IMM,2, 140,2,"CPX",IMM,4, 141,1,"BSR",REL,6, 142,2,"LDS",IMM,3, 144,1,"SUBA",DIR,3, 145,1,"CMPA",DIR,3, 146,1,"SBCA",DIR,3, 148,1,"ANDA",DIR,3, 149,1,"BITA",DIR,3, 150,1,"LDAA",DIR,3, 151,1,"STAA",DIR,3, 152,1,"EORA",DIR,3, 153,1,"ADCA",DIR,3, 154,1,"ORAA",DIR,3, 155,1,"ADDA",DIR,3, 156,1,"CPX",DIR,5, 158,1,"LDS",DIR,4, 159,1,"STS",DIR,4, 160,1,"SUBA",IND,4, 161,1,"CMPA",IND,4, 162,1,"SBCA",IND,4, 164,1,"ANDA",IND,4, 165,1,"BITA",IND,4, 166,1,"LDAA",IND,4, 167,1,"STAA",IND,4, 168,1,"EORA",IND,4, 169,1,"ADCA",IND,4, 170,1,"ORAA",IND,4, 171,1,"ADDA",IND,4, 172,1,"CPX",IND,6, 173,1,"JSR",IND,6, 174,1,"LDS",IND,5, 175,1,"STS",IND,5, 176,2,"SUBA",EXT,4, 177,2,"CMPA",EXT,4, 178,2,"SBCA",EXT,4, 180,2,"ANDA",EXT,4, 181,2,"BITA",EXT,4, 182,2,"LDAA",EXT,4, 183,2,"STAA",EXT,4, 184,2,"EORA",EXT,4, 185,2,"ADCA",EXT,4, 186,2,"ORAA",EXT,4, 187,2,"ADDA",EXT,4, 188,2,"CPX",EXT,6, 189,2,"JSR",EXT,6, 190,2,"LDS",EXT,5, 191,2,"STS",EXT,5, 192,1,"SUBB",IMM,2, 193,1,"CMPB",IMM,2, 194,1,"SBCB",IMM,2, 196,1,"ANDB",IMM,2, 197,1,"BITB",IMM,2, 198,1,"LDAB",IMM,2, 200,1,"EORB",IMM,2, 201,1,"ADCB",IMM,2, 202,1,"ORAB",IMM,2, 203,1,"ADDB",IMM,2, 206,2,"LDX",IMM,3, 208,1,"SUBB",DIR,3, 209,1,"CMPB",DIR,3, 210,1,"SBCB",DIR,3, 212,1,"ANDB",DIR,3, 213,1,"BITB",DIR,3, 214,1,"LDAB",DIR,3, 215,1,"STAB",DIR,3, 216,1,"EORB",DIR,3, 217,1,"ADCB",DIR,3, 218,1,"ORAB",DIR,3, 219,1,"ADDB",DIR,3, 222,1,"LDX",DIR,4, 223,1,"STX",DIR,4, 224,1,"SUBB",IND,4, 225,1,"CMPB",IND,4, 226,1,"SBCB",IND,4, 228,1,"ANDB",IND,4, 229,1,"BITB",IND,4, 230,1,"LDAB",IND,4, 231,1,"STAB",IND,4, 232,1,"EORB",IND,4, 233,1,"ADCB",IND,4, 234,1,"ORAB",IND,4, 235,1,"ADDB",IND,4, 238,1,"LDX",IND,5, 239,1,"STX",IND,5, 240,2,"SUBB",EXT,4, 241,2,"CMPB",EXT,4, 242,2,"SBCB",EXT,4, 244,2,"ANDB",EXT,4, 245,2,"BITB",EXT,4, 246,2,"LDAB",EXT,4, 247,2,"STAB",EXT,4, 248,2,"EORB",EXT,4, 249,2,"ADCB",EXT,4, 250,2,"ORAB",EXT,4, 251,2,"ADDB",EXT,4, 254,2,"LDX",EXT,5, 255,2,"STX",EXT,4, }; int count; /* current program counter for disasm */ /* getbyte() - get a byte from a file, and increment the byte counter */ int getbyte(FILE *fp) { int c; count++; c=getc(fp); return(c); } #ifdef NOCONST /* TFB had to undefine const */ #define const #endif BOOL PC=FALSE; /* to see if a PUL instr is pulling PC */ #define LABELSIZE 40 /* label structure */ struct lastruct { unsigned short lab; /* label address */ char label[LABELSIZE]; /* label text */ } *labarray=NULL; int numlab=0; /* number of labels defined */ #ifndef AMIGA /* hmmm, these aren't ANSI */ /* stricmp() - compare two strings, case insensitive */ int stricmp(const char *s1, const char *s2) { for(;toupper(*s1)==toupper(*s2);++s1,++s2) if(*s1=='\0') return(0); return((toupper(*(unsigned char *)s1)=256)||dosmall) { for(i=0;i15) offset=offset-32; for(sp=strlen(str);sp=*numlab) (*numlab)++; } else printf("Too many labels\n"); } else if(!strnicmp(line,"DATA ",5)) { if(*numdatacommarray[*curcomm].comline+numoperands)&& (*curcomm=commarray[*curcomm].comline)|| ((line==commarray[*curcomm].comline)&&(numoperands==1))|| (((line-1)==commarray[*curcomm].comline)&&(numoperands==0))) { if(*curcomm>=numcomm) break; if(first_comment!=TRUE) { printf("%s\n",out); out[0]='\0'; } for(sp=strlen(out);sp0) { if(*curcommlinecommlinearray[*curcommline].comline)&& (*curcommline127) { data-=128; newl=TRUE; } else newl=FALSE; if(data<10) data+=48; else if(data==10) data=32; else if(data<37) data+=54; else if(data<51) data=(int)wchars[data-37]; else data=39; return((char)data); } BOOL diddata=FALSE; int dumpdata(int opcode,int *curdata,int numdata,FILE *fp, int *curcomm,int numcomm,int *curcommline,int numcommline) { int pnum,tnum; int numoperands; int k; int numchars=0; numoperands=2+dataarray[*curdata].end-count; pnum=dataarray[*curdata].per_line; /* print up to pnum bytes data */ if(dataarray[*curdata].type==DATA) { sprintf(out2,"%02X ",(UBYTE)opcode); strcat(out,out2); if((pnum<1)||(pnum>24)) pnum=16; /* no more than 24 bytes hex data */ } else { if(dataarray[*curdata].type==ASCII) out2[0]=opcode; else out2[0]=wtext(opcode); out2[1]='\0'; strcat(out,out2); if((pnum<1)||(pnum>70)) pnum=32; /* no more than 70 bytes ASCII data */ } newl=FALSE; tnum=(pnum>numoperands)?numoperands-2:pnum-1; for(k=0;k=pnum)||newl) { if((tnum)||(pnum==1)) { docomment(count-tnum,curcomm,numcomm,tnum); docommline(count-tnum,curcommline,numcommline); } printf("%s\n",out); sprintf(out,"%04X: ",count); numchars=0; newl=FALSE; } if(dataarray[*curdata].type==DATA) sprintf(out2,"%02X ",getbyte(fp)); /* hex */ else { if(dataarray[*curdata].type==ASCII) out2[0]=getbyte(fp); /* ASCII */ else out2[0]=wtext(getbyte(fp)); /* text */ out2[1]='\0'; } strcat(out,out2); } if(*curdata1) { if(!stricmp(argv[1],"list")) { /* show all instructions */ for(i=0;i2) readdatafile(argv[2],&org,&numlab,&numdata,&numcomm,&numcommline); if(org>-1) /* int PC to ORG val or 0 */ count=org; else count=0; for(k=0;kdataarray[curdata].end)&& (curdata=dataarray[curdata].start)&& /* data? */ ((count-1)<=dataarray[curdata].end)) { numoperands=dumpdata(opcode,&curdata,numdata,fp, &curcomm,numcomm,&curcommline,numcommline); i=NUMOPS+1; /* skip decoding as an opcode */ } else { /* not data - search for opcode */ sprintf(out2,"%02X ",(UBYTE)opcode); strcat(out,out2); for(i=0;(iname,"BRA"))|| /* extra space - branch */ (!stricmp(op->name,"RTS"))|| (!stricmp(op->name,"JMP"))|| (!stricmp(op->name,"RTI"))|| (!stricmp(op->name,"WAI"))) { if(strlen(out)&&(out[strlen(out)-1]!='\n')) strcat(out,"\n"); } } if(diddata) { if(strlen(out)&&(out[strlen(out)-1]!='\n')) strcat(out,"\n"); } printf("%s\n",out); PC=FALSE; diddata=FALSE; } fclose(fp); } else fprintf(stderr,"Can't open file `%s'\n",argv[1]); } } else printf("Usage: `%s []'\n",argv[0]); freearrays(); }