/* 6809dasm.c - a 6809 opcode disassembler */ /* Version 1.4 1-MAR-95 */ /* Copyright © 1995 Sean Riddle */ /* thanks to Franklin Bowen for bug fixes, ideas */ /* 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: */ /* sriddle@ionet.net */ /* latest version at: */ /* Please don't hurl on my URL! */ /* the data files must be kept compatible across systems! */ /* usage: 6809disasm [] */ /* 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 6809dasm 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. */ /* compiled on Amiga SAS/C 6.51 and Sun 10 Unix cc */ #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 19 #define TABOPERAND 25 #define TABCOMM 40 #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; /* 6809 ADDRESSING MODES */ #define INH 0 #define DIR 1 #define IND 2 #define REL 3 #define EXT 4 #define IMM 5 #define LREL 6 #define PG2 7 /* PAGE SWITCHES - Page 2 */ #define PG3 8 /* Page 3 */ /* number of opcodes in each page */ #define NUMPG1OPS 223 #define NUMPG2OPS 38 #define NUMPG3OPS 9 int numops[3]={ NUMPG1OPS,NUMPG2OPS,NUMPG3OPS, }; char modenames[9][14]={ "inherent", "direct", "indexed", "relative", "extended", "immediate", "long relative", "page 2", "page 3", }; opcodeinfo pg1opcodes[NUMPG1OPS]={ /* page 1 ops */ 0,1,"NEG",DIR,6, 3,1,"COM",DIR,6, 4,1,"LSR",DIR,6, 6,1,"ROR",DIR,6, 7,1,"ASR",DIR,6, 8,1,"ASL",DIR,6, 9,1,"ROL",DIR,6, 10,1,"DEC",DIR,6, 12,1,"INC",DIR,6, 13,1,"TST",DIR,6, 14,1,"JMP",DIR,3, 15,1,"CLR",DIR,6, 16,1,"page2",PG2,0, 17,1,"page3",PG3,0, 18,0,"NOP",INH,2, 19,0,"SYNC",INH,4, 22,2,"LBRA",LREL,5, 23,2,"LBSR",LREL,9, 25,0,"DAA",INH,2, 26,1,"ORCC",IMM,3, 28,1,"ANDCC",IMM,3, 29,0,"SEX",INH,2, 30,1,"EXG",IMM,8, 31,1,"TFR",IMM,6, 32,1,"BRA",REL,3, 33,1,"BRN",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,1,"LEAX",IND,2, 49,1,"LEAY",IND,2, 50,1,"LEAS",IND,2, 51,1,"LEAU",IND,2, 52,1,"PSHS",INH,5, 53,1,"PULS",INH,5, 54,1,"PSHU",INH,5, 55,1,"PULU",INH,5, 57,0,"RTS",INH,5, 58,0,"ABX",INH,3, 59,0,"RTI",INH,6, 60,1,"CWAI",IMM,20, 61,0,"MUL",INH,11, 63,0,"SWI",INH,19, 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,7, 115,2,"COM",EXT,7, 116,2,"LSR",EXT,7, 118,2,"ROR",EXT,7, 119,2,"ASR",EXT,7, 120,2,"ASL",EXT,7, 121,2,"ROL",EXT,7, 122,2,"DEC",EXT,7, 124,2,"INC",EXT,7, 125,2,"TST",EXT,7, 126,2,"JMP",EXT,4, 127,2,"CLR",EXT,7, 128,1,"SUBA",IMM,2, 129,1,"CMPA",IMM,2, 130,1,"SBCA",IMM,2, 131,2,"SUBD",IMM,4, 132,1,"ANDA",IMM,2, 133,1,"BITA",IMM,2, 134,1,"LDA",IMM,2, 136,1,"EORA",IMM,2, 137,1,"ADCA",IMM,2, 138,1,"ORA",IMM,2, 139,1,"ADDA",IMM,2, 140,2,"CMPX",IMM,4, 141,1,"BSR",REL,7, 142,2,"LDX",IMM,3, 144,1,"SUBA",DIR,4, 145,1,"CMPA",DIR,4, 146,1,"SBCA",DIR,4, 147,1,"SUBD",DIR,6, 148,1,"ANDA",DIR,4, 149,1,"BITA",DIR,4, 150,1,"LDA",DIR,4, 151,1,"STA",DIR,4, 152,1,"EORA",DIR,4, 153,1,"ADCA",DIR,4, 154,1,"ORA",DIR,4, 155,1,"ADDA",DIR,4, 156,1,"CPX",DIR,6, 157,1,"JSR",DIR,7, 158,1,"LDX",DIR,5, 159,1,"STX",DIR,5, 160,1,"SUBA",IND,4, 161,1,"CMPA",IND,4, 162,1,"SBCA",IND,4, 163,1,"SUBD",IND,6, 164,1,"ANDA",IND,4, 165,1,"BITA",IND,4, 166,1,"LDA",IND,4, 167,1,"STA",IND,4, 168,1,"EORA",IND,4, 169,1,"ADCA",IND,4, 170,1,"ORA",IND,4, 171,1,"ADDA",IND,4, 172,1,"CPX",IND,6, 173,1,"JSR",IND,7, 174,1,"LDX",IND,5, 175,1,"STX",IND,5, 176,2,"SUBA",EXT,5, 177,2,"CMPA",EXT,5, 178,2,"SBCA",EXT,5, 179,2,"SUBD",EXT,7, 180,2,"ANDA",EXT,5, 181,2,"BITA",EXT,5, 182,2,"LDA",EXT,5, 183,2,"STA",EXT,5, 184,2,"EORA",EXT,5, 185,2,"ADCA",EXT,5, 186,2,"ORA",EXT,5, 187,2,"ADDA",EXT,5, 188,2,"CPX",EXT,7, 189,2,"JSR",EXT,8, 190,2,"LDX",EXT,6, 191,2,"STX",EXT,6, 192,1,"SUBB",IMM,2, 193,1,"CMPB",IMM,2, 194,1,"SBCB",IMM,2, 195,2,"ADDD",IMM,4, 196,1,"ANDB",IMM,2, 197,1,"BITB",IMM,2, 198,1,"LDB",IMM,2, 200,1,"EORB",IMM,2, 201,1,"ADCB",IMM,2, 202,1,"ORB",IMM,2, 203,1,"ADDB",IMM,2, 204,2,"LDD",IMM,3, 206,2,"LDU",IMM,3, 208,1,"SUBB",DIR,4, 209,1,"CMPB",DIR,4, 210,1,"SBCB",DIR,4, 211,1,"ADDD",DIR,6, 212,1,"ANDB",DIR,4, 213,1,"BITB",DIR,4, 214,1,"LDB",DIR,4, 215,1,"STB",DIR,4, 216,1,"EORB",DIR,4, 217,1,"ADCB",DIR,4, 218,1,"ORB",DIR,4, 219,1,"ADDB",DIR,4, 220,1,"LDD",DIR,5, 221,1,"STD",DIR,5, 222,1,"LDU",DIR,5, 223,1,"STU",DIR,5, 224,1,"SUBB",IND,4, 225,1,"CMPB",IND,4, 226,1,"SBCB",IND,4, 227,1,"ADDD",IND,6, 228,1,"ANDB",IND,4, 229,1,"BITB",IND,4, 230,1,"LDB",IND,4, 231,1,"STB",IND,4, 232,1,"EORB",IND,4, 233,1,"ADCB",IND,4, 234,1,"ORB",IND,4, 235,1,"ADDB",IND,4, 236,1,"LDD",IND,5, 237,1,"STD",IND,5, 238,1,"LDU",IND,5, 239,1,"STU",IND,5, 240,2,"SUBB",EXT,5, 241,2,"CMPB",EXT,5, 242,2,"SBCB",EXT,5, 243,2,"ADDD",EXT,7, 244,2,"ANDB",EXT,5, 245,2,"BITB",EXT,5, 246,2,"LDB",EXT,5, 247,2,"STB",EXT,5, 248,2,"EORB",EXT,5, 249,2,"ADCB",EXT,5, 250,2,"ORB",EXT,5, 251,2,"ADDB",EXT,5, 252,2,"LDD",EXT,6, 253,2,"STD",EXT,6, 254,2,"LDU",EXT,6, 255,2,"STU",EXT,6, }; opcodeinfo pg2opcodes[NUMPG2OPS]={ /* page 2 ops 10xx*/ 33,3,"LBRN",LREL,5, 34,3,"LBHI",LREL,5, 35,3,"LBLS",LREL,5, 36,3,"LBCC",LREL,5, 37,3,"LBCS",LREL,5, 38,3,"LBNE",LREL,5, 39,3,"LBEQ",LREL,5, 40,3,"LBVC",LREL,5, 41,3,"LBVS",LREL,5, 42,3,"LBPL",LREL,5, 43,3,"LBMI",LREL,5, 44,3,"LBGE",LREL,5, 45,3,"LBLT",LREL,5, 46,3,"LBGT",LREL,5, 47,3,"LBLE",LREL,5, 63,2,"SWI2",INH,20, 131,3,"CMPD",IMM,5, 140,3,"CMPY",IMM,5, 142,3,"LDY",IMM,4, 147,2,"CMPD",DIR,7, 156,2,"CMPY",DIR,7, 158,2,"LDY",DIR,6, 159,2,"STY",DIR,6, 163,2,"CMPD",IND,7, 172,2,"CMPY",IND,7, 174,2,"LDY",IND,6, 175,2,"STY",IND,6, 179,3,"CMPD",EXT,8, 188,3,"CMPY",EXT,8, 190,3,"LDY",EXT,7, 191,3,"STY",EXT,7, 206,3,"LDS",IMM,4, 222,2,"LDS",DIR,6, 223,2,"STS",DIR,6, 238,2,"LDS",IND,6, 239,2,"STS",IND,6, 254,3,"LDS",EXT,7, 255,3,"STS",EXT,7, }; opcodeinfo pg3opcodes[NUMPG3OPS]={ /* page 3 ops 11xx */ 63,1,"SWI3",INH,20, 131,3,"CMPU",IMM,5, 140,3,"CMPS",IMM,5, 147,2,"CMPU",DIR,7, 156,2,"CMPS",DIR,7, 163,2,"CMPU",IND,7, 172,2,"CMPS",IND,7, 179,3,"CMPU",EXT,8, 188,3,"CMPS",EXT,8, }; opcodeinfo *pgpointers[3]={ pg1opcodes,pg2opcodes,pg3opcodes, }; 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 const char *regs[5]={"X","Y","U","S","PC"}; const char *teregs[16]={"D","X","Y","U","S","PC","inv","inv","A","B","CC", "DP","inv","inv","inv","inv"}; 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)>5)&0x3; pb2=pb&0x8f; if((pb2==0x88)||(pb2==0x8c)) { /* 8-bit offset */ offset=getbyte(fp); sprintf(out2,"%02hX ",offset); strcat(str,out2); if(offset>127) /* convert to signed */ offset=offset-256; if(pb==0x8c) reg=4; for(sp=strlen(str);sp=0) sprintf(out2,"$%02X,%s",offset,regs[reg]); else sprintf(out2,"-$%02X,%s",-offset,regs[reg]); strcat(str,out2); if(pb==0x8c) { sprintf(out2," ; ($%04X)",offset+count); strcat(str,out2); } } else if((pb2==0x89)||(pb2==0x8d)||(pb2==0x8f)) { /* 16-bit */ offset=(getbyte(fp)<<8); sprintf(out2,"%02X ",offset>>8); strcat(str,out2); offset+=getbyte(fp); sprintf(out2,"%02X ",offset&0xff); strcat(str,out2); if((pb!=0x8f)&&(offset>32767)) offset=offset-65536; offset&=0xffff; if(pb==0x8d) reg=4; for(sp=strlen(str);sp=0) sprintf(out2,"$%04X,%s",offset,regs[reg]); else sprintf(out2,"-$%04X,%s",offset,regs[reg]); strcat(str,out2); if(pb==0x8d) { sprintf(out2," ; ($%04X)",offset+count); strcat(str,out2); } } else if(pb&0x80) { for(sp=strlen(str);sp15) offset=offset-32; for(sp=strlen(str);sp>4)&0xf], teregs[operandarray[0]&0xf]); strcat(str,out2); } else if((opcode==0x34)||(opcode==0x36)) { /* PUSH */ comma=FALSE; if(operandarray[0]&0x80) { strcat(str,"PC"); comma=TRUE; PC=TRUE; } if(operandarray[0]&0x40) { if(comma) strcat(str,","); if((opcode==0x34)||(opcode==0x35)) strcat(str,"U"); else strcat(str,"S"); comma=TRUE; } if(operandarray[0]&0x20) { if(comma) strcat(str,","); strcat(str,"Y"); comma=TRUE; } if(operandarray[0]&0x10) { if(comma) strcat(str,","); strcat(str,"X"); comma=TRUE; } if(operandarray[0]&0x8) { if(comma) strcat(str,","); strcat(str,"DP"); comma=TRUE; } if(operandarray[0]&0x4) { if(comma) strcat(str,","); strcat(str,"B"); comma=TRUE; } if(operandarray[0]&0x2) { if(comma) strcat(str,","); strcat(str,"A"); comma=TRUE; } if(operandarray[0]&0x1) { if(comma) strcat(str,","); strcat(str,"CC"); } } else if((opcode==0x35)||(opcode==0x37)) { /* PULL */ comma=FALSE; if(operandarray[0]&0x1) { strcat(str,"CC"); comma=TRUE; } if(operandarray[0]&0x2) { if(comma) strcat(str,","); strcat(str,"A"); comma=TRUE; } if(operandarray[0]&0x4) { if(comma) strcat(str,","); strcat(str,"B"); comma=TRUE; } if(operandarray[0]&0x8) { if(comma) strcat(str,","); strcat(str,"DP"); comma=TRUE; } if(operandarray[0]&0x10) { if(comma) strcat(str,","); strcat(str,"X"); comma=TRUE; } if(operandarray[0]&0x20) { if(comma) strcat(str,","); strcat(str,"Y"); comma=TRUE; } if(operandarray[0]&0x40) { if(comma) strcat(str,","); if((opcode==0x34)||(opcode==0x35)) strcat(str,"U"); else strcat(str,"S"); comma=TRUE; } if(operandarray[0]&0x80) { if(comma) strcat(str,","); strcat(str,"PC"); strcat(str," ;(PUL? PC=RTS)"); PC=TRUE; } } else { if(numoperands==2) { strcat(str,checklabs((operandarray[0]<<8)+operandarray[1], FALSE,TRUE)); } else { if(printdollar) strcat(str,"$"); for(i=0;i=*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);spcommlinearray[*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[0]+1; /* skip decoding as an opcode */ } else { /* not data - search for opcode */ sprintf(out2,"%02X ",(UBYTE)opcode); strcat(out,out2); for(i=0;(i=PG2) { /* page switch */ opcode=getbyte(fp); sprintf(out2,"%02X ",(UBYTE)opcode); strcat(out,out2); page=pg1opcodes[i].mode-PG2+1; /* get page # */ for(k=0;(kname,"BRA"))|| /* extra space - branch */ (!stricmp(op->name,"LBRA"))|| (!stricmp(op->name,"RTS"))|| (!stricmp(op->name,"JMP"))|| (!stricmp(op->name,"RTI"))|| (!strnicmp(op->name,"PUL",3)&&PC)|| /* PUL? PC=RTS */ (!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(); }