/* 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: */

/* <a href="http://www.ionet.net/~sriddle">Please don't hurl on my URL!</a> */



/* the data files must be kept compatible across systems! */



/* usage: 6809disasm <file> [<data file>] */

/* 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 <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>



/* 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)<toupper(*(unsigned char *)s2))?-1:1);

}



/* strnicmp() - compare two strings, case insensitive, length limited */

int strnicmp(const char *s1, const char *s2, size_t n) {

   for(;0<n;++s1,++s2,--n)

      if(toupper(*s1)!=toupper(*s2))

         return((toupper(*(unsigned char *)s1)<

               toupper(*(unsigned char *)s2))?-1:1);

      else if(*s1=='\0')

         return(0);

   return(0);

}

#endif



char labtemp[30];                   /* global return for checklabs() - tsk */



/* checklabs() - check the defined labels from data file */

/* substitute label for address if found */

char *checklabs(int address,BOOL lab2,BOOL printdollar) {

   int i;

   

   address&=0xffff;

   labtemp[0]='\0';

   for(i=0;i<numlab;i++)

      if(address==labarray[i].lab) {

         sprintf(labtemp,"%s",labarray[i].label);

         if(lab2)

            strcat(labtemp,":\n");

         i=numlab;

      }

   if(!strlen(labtemp)&&!lab2) {

      if(printdollar)

         sprintf(labtemp,"$%04hX",address);

      else

         sprintf(labtemp,"%04hX",address);

   }

   return(labtemp);

}



/* printoperands() - print operands for the given opcode */

void printoperands(int opcode,UBYTE numoperands,UBYTE *operandarray,

      UBYTE mode,FILE *fp,char *opname,char *str) {

   int i,rel,pb,offset=0,reg,pb2;

   BOOL comma;

   char out2[80];

   int sp;

   BOOL printdollar;                  /* print a leading $? before address */



   printdollar=FALSE;

   PC=FALSE;

   if((opcode!=0x1f)&&(opcode!=0x1e)) {

      switch(mode) {                              /* print before operands */

         case IMM:

            strcat(str,"#");

         case DIR:

         case EXT:

            printdollar=TRUE;

            break;

         default:

            break;

      }

   }

   switch(mode) {

      case REL:                                          /* 8-bit relative */

         rel=operandarray[0];

         sprintf(out2,checklabs((short)(count+((rel<128) ? rel : rel-256)),

               FALSE,TRUE));

         strcat(str,out2);

         break;

      case LREL:                                   /* 16-bit long relative */

         rel=(operandarray[0]<<8)+operandarray[1];

         sprintf(out2,checklabs(count+((rel<32768) ? rel : rel-65536),

               FALSE,TRUE));

         strcat(str,out2);

         break;

      case IND:                                  /* indirect- many flavors */

         pb=operandarray[0];

         reg=(pb>>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<OPNAMETAB;sp++)

               strcat(str," ");

            sprintf(out2,"%s",opname);

            strcat(str,out2);

            for(sp=strlen(str);sp<OPERANDTAB;sp++)

               strcat(str," ");

            if((pb&0x90)==0x90)

               strcat(str,"[");

            if(pb==0x8c)

               sprintf(out2,"%s,%s",checklabs(offset,FALSE,TRUE),regs[reg]);

            else if(offset>=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<OPNAMETAB;sp++)

               strcat(str," ");

            sprintf(out2,"%s",opname);

            strcat(str,out2);

            for(sp=strlen(str);sp<OPERANDTAB;sp++)

               strcat(str," ");

            if((pb&0x90)==0x90)

               strcat(str,"[");

            if(pb==0x8d)

               sprintf(out2,"%s,%s",checklabs(offset,FALSE,TRUE),regs[reg]);

            else if(offset>=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);sp<OPNAMETAB;sp++)

               strcat(str," ");

            sprintf(out2,"%s",opname);

            strcat(str,out2);

            for(sp=strlen(str);sp<OPERANDTAB;sp++)

               strcat(str," ");

            if((pb&0x90)==0x90)

               strcat(str,"[");

            if((pb&0x8f)==0x80) {

               sprintf(out2,",%s+",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x81) {

               sprintf(out2,",%s++",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x82) {

               sprintf(out2,",-%s",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x83) {

               sprintf(out2,",--%s",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x84) {

               sprintf(out2,",%s",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x85) {

               sprintf(out2,"B,%s",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x86) {

               sprintf(out2,"A,%s",regs[reg]);

               strcat(str,out2);

            } else if((pb&0x8f)==0x8b) {

               sprintf(out2,"D,%s",regs[reg]);

               strcat(str,out2);

            }

         } else {                                          /* 5-bit offset */

            offset=pb&0x1f;

            if(offset>15)

               offset=offset-32;

            for(sp=strlen(str);sp<OPNAMETAB;sp++)

               strcat(str," ");

            sprintf(out2,"%s",opname);

            strcat(str,out2);

            for(sp=strlen(str);sp<OPERANDTAB;sp++)

               strcat(str," ");

            sprintf(out2,"%s,%s",checklabs(offset,FALSE,TRUE),regs[reg]);

            strcat(str,out2);

         }

         if((pb&0x90)==0x90)

            strcat(str,"]");

         break;

      default:

         if((opcode==0x1f)||(opcode==0x1e)) {                   /* TFR/EXG */

            sprintf(out2,"%s,%s",teregs[(operandarray[0]>>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<numoperands;i++) {

                  sprintf(out2,"%02X",operandarray[i]);

                  strcat(str,out2);

               }

            }

         }

         break;

   }

}



#define DATA 0                                  /* type of data to display */

#define ASCII 1

#define WTEXT 2



/* DATA/ASCII structure definition */

struct dastruct {

   unsigned short start;                /* beginning address of DATA/ASCII */

   unsigned short end;                                   /* ending address */

   unsigned short per_line;                   /* values to print on a line */

   short type;                                           /* DATA or ASCII ? */

} *dataarray=NULL;



#define COMMENTSIZE 80

/* COMMENT/COMMENTLINE structure definition */

struct castruct {

   unsigned short comline;                         /* comment line address */

   char comment[COMMENTSIZE];                              /* comment text */

} *commarray=NULL,*commlinearray=NULL;



char out[512],out2[80];                             /* temp string buffers */



void readdatafile(char *filename,

      int *org,int *numlab,int *numdata,int *numcomm,int *numcommline) {

   char line2[256];

   char *line;

   FILE *fp;

   int dataline,data,data2,per_line,i,k;

   

   if(fp=fopen(filename,"r")) {                          /* read data file */

      while(fgets(line2,255,fp)) {

         while(strlen(line2)&&!isprint(line2[strlen(line2)-1])) /* strip cr */

            line2[strlen(line2)-1]='\0';

         for(i=0;i<strlen(line2);i++)

            if((line2[i]==';')||isalpha(line2[i])) {

               line= &(line2[i]);

               i=strlen(line2);

            }

         if(!strnicmp(line,"ORG ",4)) {

            if(*org==-1)

               sscanf(&line[4],"%X",org);

            else

               printf("More than one ORG line\n");

         } else if(!strnicmp(line,"LABEL ",6)) {

            if(*numlab<MAXLABEL) {

               sscanf(&line[6],"%X",&dataline);

               labarray[*numlab].lab=dataline;

               k=6;

               while(line[k]==' ')

                  k++;

               while(line[k]!=' ')

                  k++;

               while(line[k]==' ')

                  k++;

               strncpy(labarray[*numlab].label,&line[k],LABELSIZE);

               labarray[*numlab].label[LABELSIZE-1]=0;  /* just in case */

               for(i=0;i<*numlab;i++)

                  if(!strcmp(labarray[i].label,labarray[*numlab].label)) {

                     printf("duplicate label: %s\n",labarray[i].label);

                     break;

                  }

               if(i>=*numlab)   

                  (*numlab)++;

            } else

               printf("Too many labels\n");

         } else if(!strnicmp(line,"DATA ",5)) {

            if(*numdata<MAXDATA) {

               data2=0;

               sscanf(&line[5],"%X-%X",&data,&data2);

               k=5;

               while(line[k]==' ')

                  k++;

               while(line[k]!=' ')

                  k++;

               while(line[k]==' ')

                  k++;

               if (k < i)

                  sscanf(&(line[k]),"%d",&per_line);

               else

                  per_line = 0;

               if(data2<data)

                  data2=data;

               dataarray[*numdata].type=DATA;

               dataarray[*numdata].start=data;

               dataarray[*numdata].end=data2;

               dataarray[*numdata].per_line=per_line;

               if(((*numdata)&&(dataarray[*numdata-1].start<

                     dataarray[*numdata].start))||!*numdata)

                  (*numdata)++;

               else

                  printf("`%s'\nDATA out of order\n\n",line);

            } else

               printf("Too many DATA/ASCII lines\n");

         } else if(!strnicmp(line,"ASCII ",6)) {

            if(*numdata<MAXDATA) {

               data2=0;

               per_line=0;

               sscanf(&line[6],"%X-%X %d",&data,&data2,&per_line);

               if(data2<data)

                  data2=data;

               dataarray[*numdata].type=ASCII;

               dataarray[*numdata].start=data;

               dataarray[*numdata].end=data2;

               dataarray[*numdata].per_line=per_line;

               if(((*numdata)&&(dataarray[*numdata-1].start<

                     dataarray[*numdata].start))||!*numdata)

                  (*numdata)++;

               else if(*numdata)

                  printf("`%s'\nASCII out of order\n\n",line);

            } else

               printf("Too many DATA/ASCII lines\n");

         } else if(!strnicmp(line,"WTEXT ",6)) {

            if(*numdata<MAXDATA) {

               data2=0;

               per_line=0;

               sscanf(&line[6],"%X-%X %d",&data,&data2,&per_line);

               if(data2<data)

                  data2=data;

               dataarray[*numdata].type=WTEXT;

               dataarray[*numdata].start=data;

               dataarray[*numdata].end=data2;

               dataarray[*numdata].per_line=per_line;

               if(((*numdata)&&(dataarray[*numdata-1].start<

                     dataarray[*numdata].start))||!*numdata)

                  (*numdata)++;

               else if(*numdata)

                  printf("`%s'\nWTEXT out of order\n\n",line);

            } else

               printf("Too many DATA/ASCII lines\n");

         } else if(!strnicmp(line,"COMMENT ",8)) {

            if(*numcomm<MAXCOMMENT) {

               sscanf(&line[8],"%X",&dataline);

               commarray[*numcomm].comline=dataline;

                              

               k=8;

               while(line[k]==' ')

                  k++;

               while(line[k]!=' ')

                  k++;

               while(line[k]==' ')

                  k++;

               strncpy(commarray[*numcomm].comment,&line[k],COMMENTSIZE);

               commarray[*numcomm].comment[COMMENTSIZE-1]=0; /* in case */



               if(((*numcomm)&&(commarray[(*numcomm)-1].comline<=

                     commarray[*numcomm].comline))||!*numcomm)

                  (*numcomm)++;

               else

                  printf("`%s'\nCOMMENT out of order\n\n",line);

            } else

               printf("Too many COMMENT lines\n");

         } else if(!strnicmp(line,"COMMENTLINE ",12)) {

            if(*numcommline<MAXCOMMLINE) {

               sscanf(&line[12],"%X",&dataline);

               commlinearray[*numcommline].comline=dataline;

               k=12;

               while(line[k]==' ')

                  k++;

               while(line[k]!=' ')

                  k++;

               while(line[k]==' ')

                  k++;

               strncpy(commlinearray[*numcommline].comment,

                     &line[k],COMMENTSIZE);

               commlinearray[*numcommline].comment[COMMENTSIZE-1]=0;

               

               if(((*numcommline)&&(commlinearray[(*numcommline)-1].comline<=

                     commlinearray[*numcommline].comline))||!*numcommline)

                  (*numcommline)++;

               else

                  printf("`%s'\nCOMMENTLINE out of order\n\n",line);

            } else

               printf("Too many COMMENTLINE lines\n");

         } else if(line[0]==';')                    /* remark in data file */

            ;

         else if(strlen(line))

            printf("`%s'\nError in file `%s'\n\n",line,filename);

      }

      fclose(fp);

   } else

      fprintf(stderr,"Can't open file `%s'\n",filename);

}



void docomment(int line,int *curcomm,int numcomm,int numoperands) {

   int  sp;

   BOOL first_comment = TRUE;



   if(!numcomm)

      return;

   if(*curcomm<numcomm) {                 /* see if we've passed a comment */

      while(((line-1)>commarray[*curcomm].comline+numoperands)&&

            (*curcomm<numcomm)) {

         printf("Error: missed a comment at %X, line=%X\n",

               commarray[*curcomm].comline,line);

         (*curcomm)++;

      }



      while((((line-1)+numoperands)>=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);sp<COMMTAB;sp++)

            strcat(out," ");

         strcat(out,";");

         strcat(out,commarray[*curcomm].comment);

         (*curcomm)++;

			first_comment=FALSE;

      }

   }

}



void docommline(int line,int *curcommline,int numcommline) {

   BOOL didone=FALSE;

   

   if(!numcommline)

      return;

   if(*curcommline<numcommline) {     /* see if we've passed a comment line*/

      while(((line-1)>commlinearray[*curcommline].comline)&&

            (*curcommline<numcommline)) {

         printf("Error: missed a comment line at %X, line=%X\n",

               commlinearray[*curcommline].comline,line);

         (*curcommline)++;

      }



      while(((line-1)==commlinearray[*curcommline].comline)) {

         if(!didone)

            printf("\n");

         printf("*** %s\n",commlinearray[*curcommline].comment);

         (*curcommline)++;

         didone=TRUE;

      }



   }

}



BOOL newl=FALSE;

char wchars[15]={

   "<=-?!()',./&\":"

};



char wtext(int data) {

   if(data>127) {

      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<numoperands-1;k++) {                        /* print the data */

      if((++numchars>=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(*curdata<numdata)

      (*curdata)++;

   diddata=TRUE;

   return(numoperands-2);

}



void freearrays(void) {

   if(labarray)

      free(labarray);

   if(dataarray)

      free(dataarray);

   if(commarray)

      free(commarray);

   if(commlinearray)

      free(commlinearray);

}



BOOL mallocarrays(void) {

   BOOL gotit=FALSE;

   

   if(labarray=(struct lastruct *)malloc(sizeof(struct lastruct)*MAXLABEL))

      if(dataarray=(struct dastruct *)

            malloc(sizeof(struct dastruct)*MAXDATA))

         if(commarray=(struct castruct *)

               malloc(sizeof(struct castruct)*MAXCOMMENT))

            if(commlinearray=(struct castruct *)

                  malloc(sizeof(struct castruct)*MAXCOMMLINE))

               gotit=TRUE;

   if(!gotit)

      freearrays();

   return(gotit);

}



void main(int argc,char *argv[]) {

   int i,j,k;

   int opcode,page;

   UBYTE operand[4];

   FILE *fp;

   int org=~0;

   opcodeinfo *op;

   int numoperands;

   int sp;

   int numcomm=0,numdata=0,numcommline=0;

   int curcomm=0,curdata=0,curcommline=0;



   if(argc>1) {

      if(!stricmp(argv[1],"list")) {              /* show all instructions */

         for(i=0;i<numops[0];i++)

            printf("opcode %02X, operands %d, name %6s, mode %s, cycles %d\n",

                  pg1opcodes[i].opcode,pg1opcodes[i].numoperands,

                  pg1opcodes[i].name,

                  modenames[pg1opcodes[i].mode],pg1opcodes[i].numcycles);

         for(i=0;i<numops[1];i++)

            printf("opcode 10 %02X, operands %d, name %6s, mode %s, cycles %d\n",

                  pg2opcodes[i].opcode,pg2opcodes[i].numoperands,

                  pg2opcodes[i].name,

                  modenames[pg2opcodes[i].mode],pg2opcodes[i].numcycles);

         for(i=0;i<numops[2];i++)

            printf("opcode 11 %02X, operands %d, name %6s, mode %s, cycles %d\n",

                  pg3opcodes[i].opcode,pg3opcodes[i].numoperands,

                  pg3opcodes[i].name,

                  modenames[pg3opcodes[i].mode],pg3opcodes[i].numcycles);

      } else {

         if(!mallocarrays()) {

            printf("Can't get memory for arrays\n");

            exit(20);

         }

         if(argc>2)

            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;k<numlab;k++)                       /* print labels first */

            printf("%s EQU $%04X\n",labarray[k].label,labarray[k].lab);

         if(numlab)

            printf("\n");

         printf("ORG $%04X\n",count);

                     

         if(fp=fopen(argv[1],"rb")) {                  /* open binary file */

            while((opcode=getbyte(fp))!=EOF) {

               op=NULL;

               docommline(count,&curcommline,numcommline);



               printf(checklabs(count-1,TRUE,FALSE)); /* if add lab, print */

               sprintf(out,"%04X: ",count-1);                  /* print PC */

               

               if(numdata) {

                  while(((count-1)>dataarray[curdata].end)&&

                        (curdata<numdata)) {

                     printf("Error: missed a data line, start=%X, end=%X\n",

                           dataarray[curdata].start,dataarray[curdata].end);

                     curdata++;

                  }

               }

               if(numdata&&

                     ((count-1)>=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<numops[0])&&(pg1opcodes[i].opcode!=opcode);i++)

                     ;

               }

               if(i<numops[0]) {                           /* opcode found */

                  if(pg1opcodes[i].mode>=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;(k<numops[page])&&(opcode!=

                           pgpointers[page][k].opcode);k++)

                        ;

                     if(k!=numops[page]) {                 /* opcode found */

                        op=(opcodeinfo *) &(pgpointers[page][k]);

                        numoperands=pgpointers[page][k].numoperands;

                        for(j=0;j<numoperands-1;j++) {

                           sprintf(out2,"%02X ",(operand[j]=getbyte(fp)));

                           strcat(out,out2);

                        }

                           

                        if(pgpointers[page][k].mode!=IND) {

                           for(sp=strlen(out);sp<OPNAMETAB;sp++)

                              strcat(out," ");

                           sprintf(out2,"%s",pgpointers[page][k].name);

                           strcat(out,out2);

                           for(sp=strlen(out);sp<OPERANDTAB;sp++)

                              strcat(out," ");

                        }

                        printoperands(opcode,numoperands-1,

                              operand,pgpointers[page][k].mode,fp,

                              pgpointers[page][k].name,out);

                     } else {               /* not found in alternate page */

                        for(sp=strlen(out);sp<OPNAMETAB;sp++)

                           strcat(out," ");

                        strcat(out,"Illegal Opcode");

                     }

                  } else {                                /* page 1 opcode */

                     op=(opcodeinfo *) &(pg1opcodes[i]);

                     numoperands=pg1opcodes[i].numoperands;

                     for(j=0;j<numoperands;j++) {

                        sprintf(out2,"%02X ",(operand[j]=getbyte(fp)));

                        strcat(out,out2);

                     }

                     if(pg1opcodes[i].mode!=IND) {

                        for(sp=strlen(out);sp<OPNAMETAB;sp++)

                           strcat(out," ");

                        sprintf(out2,"%s",pg1opcodes[i].name);

                        strcat(out,out2);

                        for(sp=strlen(out);sp<OPERANDTAB;sp++)

                           strcat(out," ");

                     }

                     printoperands(opcode,numoperands,operand,

                           pg1opcodes[i].mode,fp,pg1opcodes[i].name,out);

                  }

               } else if(i==numops[0]) {            /* not found in page 1 */

                  for(sp=strlen(out);sp<OPNAMETAB;sp++)  

                     strcat(out," ");

                  strcat(out,"Illegal Opcode");

               }

               docomment(count-1-numoperands,&curcomm,numcomm,numoperands+1);

               if(op) {

                  if((!stricmp(op->name,"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 <file> [<datafile>]'\n",argv[0]);

   freearrays();

}

