mrr@rayssd.UUCP (05/28/85)
#!/bin/sh-----cut here-----cut here-----cut here-----cut here----- # This is a shell archive. # Run the following text with /bin/sh to extract. cat - << \Funky!Stuff! > ra/README The source that follows is a reverse assembler for C Power (tm) C compiler object files. It represents my first attempt at programming in C and is probably full of inconsistencies and other code which might be noxious to seasoned C programmers. I would be greatful for comments and suggestions, especially from other owners of C power, with regard to enhancing or otherwise improving this program. One minor point in its favor is that it works. I downloaded this without benefit of Xmodem or Kermit so there may be a garble or two, though I've screened the source here very carefully. Don't try to compile it on Unix - FILE is defined as int in C Power. Hope this is of use to someone. Mark Rinfret Funky!Stuff! cat - << \Funky!Stuff! > ra/openfile.c /* home-brew file extensions */ /* author: Mark R. Rinfret */ /* date: 04/19/84 */ /* filename: openfile.c */ #include <stdio.h> #include <strings.h> openfile(name,how) char *name,how; { char *xname; char c; unsigned dvc; xname = name; /* copy pointer */ dvc = 8; /* default is device 8 */ if ((c=*xname) == '#') { xname++; if (((c=*xname) == '8') || ((c=*xname) == '9')) { xname++; dvc = (8 + (c - '8')); if (*xname==':') xname++; else { printf("missing ':' in device specification\n%s\n",xname); return NULL; } } else { printf("illegal device number:\n%s\n",xname); return NULL; } } device(dvc); return (fopen(xname,how)); } Funky!Stuff! cat - << \Funky!Stuff! > ra/ra.fo .in 10 .rm 70 .ls 2 .sp 5 .ce 3 A Reverse Assembler for C Power (tm) Object Files .sp 20 .nf Mark R. Rinfret 348 Indian Ave. Portsmouth, RI 02871 (401)-846-7639 C Power is a trademark of Pro-Line Software Ltd. .fi .bp .fo //-#-// .he /ra/-#-/Reverse Assembler/ Introduction I wrote the reverse assembler to help debug an assembler which I hope to implement in the near future. The assembler will output C Power compatible object files and will be useful for implementing machine-dependent or time/space critical code not easily handled by the compiler. Original intent aside, the reverse assembler is also useful for gaining insight into the quality of machine language generated for various C language constructs and also for gleaning interface requirements as well as characteristics of the runtime library routines. Operation The reverse assembler is invoked with a command of the following form: .br ra [options] objectfile .br Currently, no special checks are made for the ".o" or ".obj" suffix indicating object file format so it is possible to invoke RA with a source file (which should yield very wierd results). RA employs a special routine, named openfile, to parse filenames. This allows users with dual 1541's to specify which device the file is on, rather than having to move the file to the work disk or play games with the 'sys' command. If the default device is to be used, the filename is specified as always. To indicate a specific drive, precede the filename with the number sign, device number (8,9) and a colon. Example: .br .ti+5 #9:ra1.obj .br The legal options are as follows: .br .in +5 -a address .br The disassembly process normally sets the address origin to $1800 (6144 decimal) which is the load address for programs linked to execute under the shell. This was done to allow the program to more reasonably differentiate between zero-page and arg buffer references when replacing numeric operands with symbols. The address value is expected to be a hex number. No range checking is applied. .sp2 -p .br RA aspires to be intelligent in its choice of formatting mode (current IQ is about 60). If a run gives poor results, you can override the internal decision-making (RA won't be offended) and RA will prompt you for the formatting mode (instruction or .byte) to be used whenever a 'transition point' is detected. If this still doesn't work, rewrite RA to do what you want. .sp 2 -l listfile .br If you want to capture the disassembly in a file, it is recommended that you use the -l option rather than simply redirecting output. Standard output is used for certain diagnostic messages as well as prompts and inputs related to the -p option. If you want hardcopy and are not using the -p option, go ahead and use >> to redirect output to the printer. If you are using -p and want hardcopy, use use the -l option and pr (or print) the resulting list file. RA performs no pagination, so the print method may be desirable for that reason, also. .br .in-5 .sp2 Implementation Details RA initializes itself by collecting the first four parts of the object file (code, relocation info, external definitions, external references) and applying the relocation address ($1800 or -a value) to the appropriate code words and all external definitions. RA then enters a loop which attempts to determine on each pass whether the code should be disassembled as 6502 instructions or as hex constants in .byte directives. This check is triggered by one of the following events: .br .in+5 Detection of an external definition whose offset coincides with the current value of the location counter. .br Detection of an external reference to the library routine C$106 which is called whenever a function exits. .br Detection of an invalid opcode. .br .in-5 .sp2 In automatic mode, the choice to use instruction mode is based on the observation that (as far as I can tell) all functions begin with a 'sta $fb' instruction. This does not hold true for runtime routines (i.e. c105.obj). Obviously, this is highly dependent on the current implementation of the compiler and, I suppose, subject to change. In spite of its shortcomings, RA has so far given quite useful and readable output from a variety of sources. As each instruction is disassembled, the external definition list is scanned to see if the operand address is the same as that of one of the external symbols. If so, the hex operand is replaced with the symbol name. This works best if the default origin is used (no -a option). After all code has been reverse assembled, all data block definitions are formatted as a series of '*=*+' directives. .br Building RA RA is currently comprised of 4 source modules as well as being dependent upon the openfile routine. These are: .in+5 .nf ra.h - Constant and structure definitions rad1.c - Global data definitions ra1.c - Initialization routines ra2.c - Translation routines .fi Once all of the sources have been compiled, they are bound by the linker as follows: .nf .ls 1 $ link > ra1.o > ra2.o > openfile.o > rad1.o > ^ > output to: ra.sh $ .fi .ls 2 Actually, I have added openfile to my system library to allow automatic resolution during the library search. .br There is a preprocessor flag, DEBUG, in ra.h which causes extra output when defined. This extra output includes code size, number of relocation entries and relocation data list, external definition count and list, and external reference count. In addition, for each line disassembled in instruction format, the raw data and location counter are printed to the left of the instruction mnemonic. The source file rad1.c (global data) contains a preprocessor flag, LOCDBG (local debug). If this flag is defined, a main routine is compiled which will print out the instruction translation tables. These tables are printed in a format easily cross-checked to the tables in the Commodore 64 Programmer's Reference manual. This main routine must not be present when the whole program is linked. .br Release I am releasing this program to the public domain for any non-profit use or redistribution. I would greatly appreciate feedback, comments, suggestions or details of any enhancements or corrections that are applied. One area for enhancement is the generation of labels for all memory references not already 'covered' by an external definition. Further work on RA by me at this time will just keep me from getting on with my assembler. Enjoy! Funky!Stuff! cat - << \Funky!Stuff! > ra/ra.h /* * Reverse Assembler * Constant and Structure Definitions * */ #include <stdio.h> #include <strings.h> #define DEBUG #define MAXID 20 /* addressing mode constants */ #define ACC 0 #define IMM 1 #define ZER 2 #define ZPX 3 #define ZPY 4 #define ABS 5 #define ABX 6 #define ABY 7 #define IMP 8 #define REL 9 #define INDX 10 #define INDY 11 #define IND 12 typedef char byte; struct label { struct label *next; /* forward linked list */ char *name; unsigned flag; unsigned offset; }; Funky!Stuff! cat - << \Funky!Stuff! > ra/ra1.c /* Object File Reverse Assembler * Author: Mark R. Rinfret * Date: 05/13/85 * Filename: ra1.c */ #include "ra.h" /* external data */ extern struct label *xdefhd,*xdeftl; /* head,tail of xdef label list */ extern struct label *xrefhd,*xreftl; /* head,tail pointers for xref list */ extern FILE lst; /* listing file */ extern FILE obj; /* object file */ extern unsigned bias,codesz,relsz,xrefsz,datasz; extern char *codebuf; /* code buffer */ extern unsigned prompt; /* interactive mode flag */ extern unsigned *relbuf; /* relocation data */ /* global data */ struct label *newlbl; /* new label pointer */ /****************/ main (argc, argv) unsigned argc; char **argv; { lst = stdout; /* default is standard output */ bias = 0x1800; /* starting address for shell programs */ prompt = 0; /* non-interactive mode */ while (argc>2) { if (!strcmp(*++argv,"-l")) { /* listing option */ if ((lst=openfile(*++argv,"w"))==NULL || ferror()) { printf("can't open listing file, %s\n",*argv); exit(); } argc -= 2; } else if (!strcmp(*argv,"-p")) { /* interactive option */ prompt = 1; argc--; } else if (!strcmp(*argv,"-a")) { /* change bias */ sscanf(*++argv,"%x",&bias); argc -= 2; } else { printf("--bad option: %s\n",*argv); exit(); } } /* end while */ if (argc<2) usage(); if ((obj = openfile(*++argv, "r")) == NULL || ferror()) { printf ("can't open object file, %s\n", *argv); } else { reverse (); fclose (obj); } } /* * Display correct program usage. * */ usage() { printf("usage: ra [options] object file\n"); printf("options:\n"); printf(" -p (enable format prompting)\n"); printf(" -l listfile (output to listfile)\n"); printf(" -a address (align at hex address)\n"); exit(); } reverse() { xdefhd = NULL; xdeftl = NULL; xrefhd = NULL; xreftl = NULL; getcode(); /* input code segment */ getrel(); /* get relocation data */ getxdef(); /* get external id's */ getxref(); /* get external ref's */ rvrs(); /* do reverse assembly */ } /* Input code segment */ getcode() { char *malloc(); codesz = getw(obj); #ifdef DEBUG fprintf(lst,"Code Size: %5d(D) / %x(X)\n",codesz,codesz); #endif codebuf = malloc(codesz); fread(codebuf,1,codesz,obj); } /* * Input relocation information and perform relocation. * */ getrel() { char *malloc(); char *cp; /* temp code pointer */ unsigned ad,cnt1,cnt2; unsigned *rp; relsz = getw(obj); relbuf = (int *) malloc(relsz*2); fread(relbuf,2,relsz,obj); #ifdef DEBUG fprintf(lst,"%d relocation entries\n",relsz); cnt1 = relsz; cnt2 = 0; rp = relbuf; while (cnt1--) { fprintf(lst,"%04x ",*rp++); if (++cnt2 == 8) { fputc('\n',lst); cnt2=0; } } fprintf(lst,"\n;--------------------\n"); #endif /* Relocate the code according to 'bias' */ rp = relbuf; cnt1 = relsz; while (cnt1--) { /* * Compute pointer into code buffer. It is important to note that the * relocation entry always assumes that an opcode is present (3 byte code * entry). Thus, relocation entries which modify character string pointers * appear to be one less than they should be. * */ cp = codebuf + *rp++ + 1; ad = *cp; /* get low byte of address */ ad = ad | (*(cp+1) << 8); /* 'or' with upper byte */ ad = ad + bias; /* relocate */ *cp = ad; /* put back lower */ *(cp+1) = (ad >> 8); /* put back upper */ } } /* Input external identifiers */ getxdef() { char *malloc(); unsigned count,i,ofst; char id[MAXID]; count = getw(obj); /* get count of id's */ #ifdef DEBUG fprintf(lst,"%d external definitions\n",count); #endif while (count--) { if (!(newlbl = (struct label *) malloc(sizeof(struct label)))) { fprintf(lst,"Out of memory!"); abort(); } getid(id,obj); /* input identifier */ newlbl->name = malloc(strlen(id)+1); strcpy(newlbl->name,id); newlbl->flag = getc(obj); ofst = getw(obj); if (newlbl->flag) ofst += bias; /* relocate symbol to start address */ newlbl->offset = ofst; newlbl->next = NULL; #ifdef DEBUG fprintf(lst,"%-12s ",newlbl->name); fprintf(lst,"%c ",(newlbl->flag ? 'R' : 'A')); fprintf(lst,"%04x\n",newlbl->offset); #endif if (xdefhd==NULL) { /* first entry */ xdefhd = newlbl; xdeftl = newlbl; } else { /* add to end of list */ xdeftl->next = newlbl; xdeftl = newlbl; } } } /* * Input external references * */ getxref() { struct label *malloc(); unsigned count; char id[MAXID]; struct label *newxref; count=getw(obj); /* get number of xrefs */ #ifdef DEBUG fprintf(lst,"%d external references.\n\n",count); #endif while (count--) { getid(id,obj); /* input identifier */ newxref=malloc(sizeof(struct label)); newxref->name = malloc(strlen(id)); strcpy(newxref->name,id); newxref->next = NULL; newxref->flag = getw(obj); newxref->offset = getw(obj)+bias; if (xrefhd==NULL) { /* first entry */ xrefhd = newxref; xreftl = newxref; } else { xreftl->next = newxref; xreftl = newxref; } } } /* * Input identifier from file, replacing 'kludge' characters * */ getid(s,f) char *s; FILE f; { char *s1; char c; s1 = s; /* save copy of pointer */ while (*s++ = getc(f)) ; if (!isalpha(*s1)) { /* kludge label? */ *s1++ = '.'; if (*s1) { /* more than 1 character? */ *s1++ = '.'; } } while (c=*s1) { /* check rest of label */ if (!isprint(c)) *s1 += ('a'-1); /* make printable character */ s1++; } } Funky!Stuff! cat - << \Funky!Stuff! > ra/ra2.c /* * Reverse Assembler * Translation Routines * Filename: ra2.c * */ #include "ra.h" /* external data */ extern FILE obj; extern FILE lst; extern struct label *xdefhd; extern struct label *xrefhd; extern char *codebuf; extern unsigned codesz,bias,datasz,prompt; extern unsigned *relbuf; extern char *mtable[]; /* mnemonic strings */ extern char opcodes[]; /* opcode to mnemonic index translation */ extern char amodes[]; /* opcode to addressing mode translation */ extern char modesz[]; /* mode to address field size */ /* * Package global data * */ char *codeptr; /* code buffer pointer */ int count; /* code counter */ char efunc; /* true when end of function detected (c$106) */ unsigned loc; /* current location */ int *relptr; /* relocation info pointer */ struct label *cursym; /* current symbol */ struct label *xdefptr,*xrefptr; /* pointer to next xdef, xref */ /* * Print address value as either a symbolic quantity or hex value * Called with: * Address, addressing mode, size (0-2) */ pav(a,m,s) unsigned a,m,s; { if (!ckref()) { /* xref pending? */ if (m != IMM) { /* don't do symbol search for immediate operands */ if (cksym(a)) return; } if (s==2) fprintf(lst,"$%04x",a); else fprintf(lst,"$%02x",a); } } /* * Print address field based on opcode * Called with: * address * addressing mode * size (0-2) */ paf(a,m,s) unsigned a,m,s; { unsigned addr; /* address value */ switch (m) /* prefix? */ { case ACC: fputc('A',lst); break; case IMM: fputc('#',lst); pav(a,m,s); break; case ZER: case ABS: pav(a,m,s); break; case ZPX: case ABX: pav(a,m,s); fprintf(lst,",X"); break; case ZPY: case ABY: pav(a,m,s); fprintf(lst,",Y"); break; case IMP: break; case REL: if (a>=128) /* sign extend */ addr = (0xff00 | a); else addr = a; addr=addr+loc+2; pav(addr,m,s); break; case INDX: fputc('(',lst); pav(a,m,s); fprintf(lst,",X)"); break; case INDY: fputc('(',lst); pav(a,m,s); fprintf(lst,"),Y"); break; case IND: fputc('(',lst); pav(a,m,s); fputc(')',lst); break; default: fprintf(lst,"????"); } } /* * Main routine for this package * */ rvrs() { char op; unsigned a1,a2,defcnt; unsigned mode,imode,size,i; codeptr = codebuf; relptr = relbuf; xdefptr = xdefhd; xrefptr = xrefhd; loc = bias; count = codesz; imode = 1; /* always start in instruction mode */ efunc = 0; fprintf(lst," *= $%04x\n",bias); while (count) { if (ckdef() || efunc) imode=ckmode(); efunc = 0; if (!opcodes[*codeptr]) { /* invalid opcode? */ fprintf(lst,";!!!Invalid opcode - switching to byte mode.\n"); imode=0; } if (imode==0) { dobyte(); if (count) imode = ckmode(); } else { /* instruction mode */ op = *codeptr++; count--; mode = amodes[op]; size = modesz[mode]; a1=0; a2=0; if (size) { a1 = *codeptr++; count--; if (size==2) { a2 = *codeptr++; count--; } } if (count<0) { fprintf(lst,"--- code underflow ---\n"); abort(); } #ifdef DEBUG fprintf(lst,"%02x %02x %02x / %04x ",op,a1,a2,loc); #endif fprintf(lst," %s ",mtable[opcodes[op]]); if (size==2) a1 = a1 | (a2 << 8); paf(a1,mode,size); /* print address field */ fputc('\n',lst); loc=loc+size+1; } /* instruction mode */ } /* while */ dodata(); /* output data blocks */ fputc('\n',lst); } /* * Format data in .byte mode until a next label definition. * */ dobyte() { unsigned bytecnt=8,first=1; while (count) { if (ckdef()) break; if (bytecnt==8) { if (!first) fputc('\n',lst); first=0; bytecnt=0; #ifdef DEBUG fprintf(lst," %04x ",loc); #endif fprintf(lst," .byte "); } fprintf(lst,"%c $%02x ",(bytecnt>0 ? ',' : ' '),*codeptr++); bytecnt++; count--; loc++; } /* while */ fputc('\n',lst); } /* * See if current location has one or more labels defined. * Returns a count of labels defined for this location. */ ckdef() { unsigned dc; dc = 0; while (xdefptr && (loc == xdefptr->offset)) { if (!dc) { fputc('\n',lst); /* skip line on first label */ fprintf(lst,";--------------------\n"); } dc++; fprintf(lst,"%s\n",xdefptr->name); cursym = xdefptr; /* save current symbol */ xdefptr = xdefptr->next; } return(dc); } /* * See if current location has an external reference. * */ ckref() { if (xrefptr && (loc == xrefptr->offset)) { /* * Here lies a kludge which assists in the determination of the formatting * mode to be used. If a reference to runtime routine C$106 is being made, * we are about to exit a function. What follows could be another function * or it could be the beginning of unlabeled preset string or array data. * The main loop tests the flag 'efunc', which is set here, to see if a mode * check is necessary. */ efunc = !strcmp(xrefptr->name,"c$106"); if (xrefptr->flag == 1) fputc('<',lst); /* high order byte */ else if (xrefptr->flag == 2) fputc('>',lst); /* low order byte */ fprintf(lst,"%s",xrefptr->name); xrefptr = xrefptr->next; if (efunc) fputc('\n',lst); return(1); } else return(0); } /* * See if address value matches external symbol definition offset * Returns symbol offset if found, zero otherwise. This assumes * that zero is an invalid offset, which in fact, it is, since the * code at zero is always a jmp c$start. */ cksym(a) unsigned a; { struct label *ptr; ptr = xdefhd; /* get xdef list pointer */ while (ptr) { /* nothing fancy - just a linear search */ if (a == ptr->offset) { fprintf(lst,"%s",ptr->name); return(ptr->offset); } ptr = ptr->next; } return(0); } /* * Check for formatting mode change. * Returns 1 for instruction mode, 0 for .byte mode * */ ckmode() { char c1,c2; /* next 2 byte values */ char s[20]; /* response string */ c1 = *codeptr; c2 = *(codeptr+1); if (prompt) { /* user wants authority */ printf("current symbol: %s\nfirst 2 bytes: %02x %02x\n",cursym->name,c1,c2); for (;;) { printf("Instruction or Byte mode? "); gets(s); switch(*s) { case 'I': case 'i': return(1); case 'B': case 'b': return(0); default: printf("Enter an I or a B, please\n"); } } } else { /********************************************************************* * Here comes the big kludge, folks! In order to decide whether the * * code that follows is instruction or data, we test for the pattern * * 'sta $fb' which seems to occur at the entry to every procedure. * * If this pattern is not detected, then we switch to data mode and * * output .byte directives. * *********************************************************************/ if ((c1==0x85) && (c2==0xfb)) return(1); /* set instruction mode */ else return(0); } } /* * Output Data Blocks * */ dodata() { unsigned cnt,size; char id[MAXID]; cnt = getw(obj); /* get number of entries */ if (cnt) { fprintf(lst,"\n;Module data blocks.\n"); #ifdef DEBUG fprintf(lst,"%d data blocks.\n",cnt); #endif while (cnt--) { getid(id,obj); /* get identifier */ size = getw(obj); fprintf(lst,"%-10s *=*+%d\n",id,size); } } } Funky!Stuff! cat - << \Funky!Stuff! > ra/rad1.c /* * Reverse Assembler Global Data * Filename: rad1.c */ #include "ra.h" #undef LOCDBG /* turn off local debug */ #define NUMOPS 57 struct label *xdefhd,*xdeftl; /* head and tail of xdef label list */ struct label *xrefhd,*xreftl; /* head and tail of xref label list */ FILE lst; /* listing file */ FILE obj; /* object file */ unsigned bias,codesz,relsz,xrefsz,datasz; unsigned prompt; /* 1 => prompt for format */ char *codebuf; /* code buffer */ unsigned *relbuf; /* relocation data */ char *mtable[]={ /* mnemonic table */ "???", /* 0 */ "adc","and","asl", /* 01-03 */ "bcc","bcs","beq", /* 04-06 */ "bit","bmi","bne", /* 07-09 */ "bpl","brk","bvc", /* 10-12 */ "bvs","clc","cld", /* 13-15 */ "cli","clv","cmp", /* 16-18 */ "cpx","cpy","dec", /* 19-21 */ "dex","dey","eor", /* 22-24 */ "inc","inx","iny", /* 25-27 */ "jmp","jsr","lda", /* 28-30 */ "ldx","ldy","lsr", /* 31-33 */ "nop","ora","pha", /* 34-36 */ "php","pla","plp", /* 37-39 */ "rol","ror","rti", /* 40-42 */ "rts","sbc","sec", /* 43-45 */ "sed","sei","sta", /* 46-48 */ "stx","sty","tax", /* 49-51 */ "tay","tsx","txa", /* 52-54 */ "txs","tya" /* 55-56 */ }; char opcodes[256]={/* opcode to mnemonic translation */ /* 00 */ 11, 35, 00, 00, 00, 35, 03, 00, /* 08 */ 37, 35, 03, 00, 00, 35, 03, 00, /* 10 */ 10, 35, 00, 00, 00, 35, 03, 00, /* 18 */ 14, 35, 00, 00, 00, 35, 03, 00, /* 20 */ 29, 02, 00, 00, 07, 02, 40, 00, /* 28 */ 39, 02, 40, 00, 07, 02, 40, 00, /* 30 */ 08, 02, 00, 00, 00, 02, 40, 00, /* 38 */ 45, 02, 00, 00, 00, 02, 40, 00, /* 40 */ 42, 24, 00, 00, 00, 24, 33, 00, /* 48 */ 36, 24, 33, 00, 28, 24, 33, 00, /* 50 */ 12, 24, 00, 00, 00, 24, 33, 00, /* 58 */ 16, 24, 00, 00, 00, 24, 33, 00, /* 60 */ 43, 01, 00, 00, 00, 01, 41, 00, /* 68 */ 38, 01, 41, 00, 28, 01, 41, 00, /* 70 */ 13, 01, 00, 00, 00, 01, 41, 00, /* 78 */ 47, 01, 00, 00, 00, 01, 41, 00, /* 80 */ 00, 48, 00, 00, 50, 48, 49, 00, /* 88 */ 23, 00, 54, 00, 50, 48, 49, 00, /* 90 */ 04, 48, 00, 00, 50, 48, 49, 00, /* 98 */ 56, 48, 55, 00, 00, 48, 00, 00, /* a0 */ 32, 30, 31, 00, 32, 30, 31, 00, /* a8 */ 52, 30, 51, 00, 32, 30, 31, 00, /* b0 */ 05, 30, 00, 00, 32, 30, 31, 00, /* b8 */ 17, 30, 53, 00, 32, 30, 31, 00, /* c0 */ 20, 18, 00, 00, 20, 18, 21, 00, /* c8 */ 27, 18, 22, 00, 20, 18, 21, 00, /* d0 */ 09, 18, 00, 00, 00, 18, 21, 00, /* d8 */ 15, 18, 00, 00, 00, 18, 21, 00, /* e0 */ 19, 44, 00, 00, 19, 44, 25, 00, /* e8 */ 26, 44, 34, 00, 19, 44, 25, 00, /* f0 */ 06, 44, 00, 00, 00, 44, 25, 00, /* f8 */ 46, 44, 00, 00, 00, 44, 25, 00 }; char amodes[256] = { /* opcode to addressing mode */ /* 00 */ IMP , INDX, IMP , IMP , IMP , ZER , ZER , IMP , /* 08 */ IMP , IMM , ACC , IMP , IMP , ABS , ABS , IMP , /* 10 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* 18 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP , /* 20 */ ABS , INDX, IMP , IMP , ZER , ZER , ZER , IMP , /* 28 */ IMP , IMM , ACC , IMP , ABS , ABS , ABS , IMP , /* 30 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* 38 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP , /* 40 */ IMP , INDX, IMP , IMP , IMP , ZER , ZER , IMP , /* 48 */ IMP , IMM , ACC , IMP , ABS , ABS , ABS , IMP , /* 50 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* 58 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP , /* 60 */ IMP , INDX, IMP , IMP , IMP , ZER , ZER , IMP , /* 68 */ IMP , IMM , ACC , IMP , IND , ABS , ABS , IMP , /* 70 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* 78 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP , /* 80 */ IMP , INDX, IMP , IMP , ZER , ZER , ZER , IMP , /* 88 */ IMP , IMP , IMP , IMP , ABS , ABS , ABS , IMP , /* 90 */ REL , INDY, IMP , IMP , ZPX , ZPX , ZPY , IMP , /* 98 */ IMP , ABY , IMP , IMP , IMP , ABX , IMP , IMP , /* a0 */ IMM , INDX, IMM , IMP , ZER , ZER , ZER , IMP , /* a8 */ IMP , IMM , IMP , ABS , ABS , ABS , ABS , IMP , /* b0 */ REL , INDY, IMP , IMP , ZPX , ZPX , ZPY , IMP , /* b8 */ IMP , ABY , IMP , IMP , ABX , ABX , ABY , IMP , /* c0 */ IMM , INDX, IMP , IMP , ZER , ZER , ZER , IMP , /* c8 */ IMP , IMM , IMP , IMP , ABS , ABS , ABS , IMP , /* d0 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* d8 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP , /* e0 */ IMM , INDX, IMP , IMP , ZER , ZER , ZER , IMP , /* e8 */ IMP , IMM , IMP , IMP , ABS , ABS , ABS , IMP , /* f0 */ REL , INDY, IMP , IMP , IMP , ZPX , ZPX , IMP , /* f8 */ IMP , ABY , IMP , IMP , IMP , ABX , ABX , IMP }; char modesz[13] = { /* ACC */ 0, /* IMM */ 1, /* ZER */ 1, /* ZPX */ 1, /* ZPY */ 1, /* ABS */ 2, /* ABX */ 2, /* ABY */ 2, /* IMP */ 0, /* REL */ 1, /* INDX*/ 1, /* INDY*/ 1, /* IND */ 2 }; char *modename[] = { "accumulator", "immediate", "zero page", "zero page,x", "zero page,y", "absolute", "absolute,x", "absolute,y", "implied", "relative", "(indirect,x)", "(indirect),y", "(indirect)" }; #ifdef LOCDBG prtop(op) unsigned op; { printf(" %02x %-3s %-12s", op,mtable[opcodes[op]], modename[amodes[op]]); } main() /* for local test only */ { unsigned i,j; for (i=0;i<=0xc0;i+= 0x40) { for (j=0;j<0x20;j++) { prtop(i+j); printf(" "); prtop(i+0x20+j); putchar('\n'); } printf("\n\n"); } putchar('\n'); } #endif Funky!Stuff! -- Mark R. RInfret, SofTech Inc. Raytheon Co.; Portsmouth RI; (401)-847-8000 x4938 ...!decvax!brunix!rayssd!mrr ...!allegra!rayssd!mrr ...!linus!rayssd!mrr