/* (c) 1990 Martin Combs */
/* Edited by Steve Hawtin to use as part of the dump program 

  This file defines the function

    void
    disass(length,fptr)
        int length;
        FILE *fptr;

this function will read the next "length" elements of the file using the 
function my_fread() and will create a disassembly listing using the 
function my_printf() to print the data out.
*/

#include <stdio.h>
#include <ctype.h>

typedef void (*voidfun)();

#ifdef NEED_MAIN
#define maxfile  20000

#endif

long i, iold;
long *lp;
unsigned int hibyte, lobyte, lonib, L76, mode, reg, reg1, size;
short *wp;
char *p;
char instS[40], opS[20], op1S[40], op2S[20], ascS[20];
char objS[40];
char reg1S[4];
char *ccS[16] =
   {  "t",  "f", "hi", "ls",
     "cc", "cs", "ne", "eq",
     "vc", "vs", "pl", "mi",
     "ge", "lt", "gt", "le" 
    };
char *shiftS[8]= 
   { "asr",  "asl", "lsr", "lsl",
    "roxr", "roxl", "ror", "rol"
    };

binst()
{ switch (L76)
    { case 0: strcpy(instS,"btst"); break;
      case 1: strcpy(instS,"bchg"); break;
      case 2: strcpy(instS,"bclr"); break;
      case 3: strcpy(instS,"bset");
    }
}

sizef()
{ switch (L76)
     { case 0: strcat(instS,".b"); size=0; break;
       case 1: strcat(instS,".w"); size=1; break;
       case 2: strcat(instS,".l"); size=2;
     }
}

sizeff()
{ sizef(); eff();
}

eff()
   {mode = (lobyte&56) >> 3;
    reg = lobyte & 7;
    eff1();
    }

eff1()
   {switch (mode)
       {case 0: 
            sprintf(opS,"d%d",reg);
            break;
        case 1:
            sprintf(opS,"a%d",reg);
            break;
        case 2:
            sprintf(opS,"(a%d)",reg);
            break;
        case 3:
            sprintf(opS,"(a%d)+",reg);
            break;
        case 4:
            sprintf(opS,"-(a%d)",reg);
            break;
        case 5:
            i+=2;
            wp=(short *)&p[i];
            sprintf(opS,"%d(a%d)",*wp,reg);
            break;
        case 6:
            i+=2;
            sprintf(opS,"%d(a%d,",p[i+1],reg);
            ariwi2();
            break;
        case 7: 
            grabbag();
        }
    }

ariwi2()
   {char regS[6];

    sprintf(regS,"%c%d.%c)",(p[i]&128)?'a':'d',((p[i] & 0x70) >> 4),
            (p[i]&8)?'l':'w');
    strcat(opS,regS);
    }

grabbag()
{ switch (reg)
    { case 0: i+=2; wp=(short *)&p[i]; sprintf(opS,"%d",*wp); break;
      case 1: i+=4; lp=(long *)&p[i-2]; sprintf(opS,"%ld",*lp); break;
      case 2: i+=2; wp=(short *)&p[i]; sprintf(opS,"%d(pc)",*wp); break;
      case 3: i+=2; sprintf(opS,"%d(pc),",p[i+1]); ariwi2(); break;
      default: switch (size)
                { case 0: i+=2; sprintf(opS,"#$%x",p[i+1]); break;
                  case 1: i+=2; wp=(short *)&p[i];
                          sprintf(opS,"#$%x",*wp); break;
                  case 2: i+=4; lp=(long *)&p[i-2];
                          sprintf(opS,"#$%lx",*lp); break;
                }
    }
}

movep()
{ if (lobyte & 64) strcpy(instS,"movep.l"); else strcpy(instS,"movep.w");
  dreg();  reg=lobyte & 7; i+=2;
  wp=(short *)&p[i];
  if (lobyte & 128) {strcpy(op1S,reg1S);sprintf(op2S,"%d(a%d)",*wp,reg);}
  else { strcpy(op2S,reg1S); sprintf(op1S,"%d(a%d)",*wp,reg); }
}

dreg()
{ reg1S[0]='d';
  reg1=(hibyte & 14) >> 1;
  reg1S[1]=reg1+48;
}
areg()
{ reg1S[0]='a';
  reg1=(hibyte & 14) >> 1;
  reg1S[1]=reg1+48;
}

move()
{ unsigned int inst;
  inst=hibyte*256+lobyte;
  if (size) { strcpy(instS,"move");
              if ((inst & 448)==64) strcat(instS,"a");
              if (size==2) strcat(instS,".l");
              else strcat(instS,".w");
              }
  eff(); strcpy(op1S,opS); mode=(inst & 448)>>6; reg=(inst & 3584) >> 9;
  eff1(); strcpy(op2S,opS);
}

movec()
{ int contreg;
  if (p[i]&128) opS[0]='a'; else opS[0]='d';
  opS[1]=48 + ((p[i] & 112) >> 4);
  opS[2]='\0';
  wp=(short *)&p[i]; contreg=(*wp)&4095;
  switch (contreg)
   { case 0: strcpy(op1S,"sfc"); break;
     case 1: strcpy(op1S,"dfc"); break;
     case 2048: strcpy(op1S,"usp"); break;
     case 2049: strcpy(op1S,"vbr"); break;
   }
}

movem()
   {char rdS[20], registerlistS[30];
    register j;
    int bm, bm1=0;
    int state = 0;
  
    if (lobyte & 64) 
        strcpy(instS,"movem.l");
      else
        strcpy(instS,"movem.w");
    eff();
    i+=2;
    wp=(short *)&p[i];
    bm=*wp;

    registerlistS[0] = '\0';

    /* Scan the bits to see which registers we have */
    for(j=0;j<16;++j)
       {/* Look at this bit */
        if(state==0 && (bm & 1<<(15-j)))
           {/* We have a register */
            sprintf(rdS,registerlistS[0]=='\0'?"%c%d":"/%c%d",
                        j>=8?'a':'d',j%8);
            strcat(registerlistS,rdS);
            state = 1;
            }
          else if (state == 1)
           {if((bm & 1<<(15-j))==0)
                state = 0;
              else if (j==7 || j==15 || (bm & 1<<(14-j))==0)
               {/* So this is the last of a set */
                sprintf(rdS,"-%c%d",j>=8?'a':'d',j%8);
                strcat(registerlistS,rdS);
                state = 0;
                }
            }
        }
    if (lonib==8)
       {strcpy(op1S,registerlistS);
        strcpy(op2S,opS);
        }
      else
       {strcpy(op1S,opS);
        strcpy(op2S,registerlistS);
        }
    }

dbcc()
{ if (lonib==1) strcpy(instS,"dbra");
  else { strcpy(opS,"db"); strcat(opS,instS); strcpy(instS,opS); }
  op1S[0]='d'; op1S[1]=48 + (lobyte & 7); op1S[2]='\0';
  i+=2; figurelabel();  sprintf(op2S,"%d",*wp);
  strcat(op2S,opS);
}

figurelabel()
{ wp=(short *)&p[i];
 sprintf(opS,"      ($%lx)",iold + 2 + *wp);
}

genasc()
   {int asc, ii, k=0;
    for (ii=iold; ii<i; ii++)
       {asc=p[ii];
        if (isprint(asc) && !(asc & 0x80))
            ascS[k++]=asc;
          else
            ascS[k++]='.';
        }
    ascS[k]='\0';
    }

genobj()
   {/* Print out the object code as hex numbers */
    int  ii;
    char pr[4];

    objS[0] = '\0';
    for (ii=0; (ii+iold)<i; ii++)
       {
        sprintf(pr,"%02x",p[ii+iold] & 0xff);
        strcat(objS,pr);
        if(ii%2)
            strcat(objS," ");
        }
    }

void
opinvalid()
   {
    strcpy(instS,"INVALID");
    }

void
op0000xxx0()
{ if (hibyte==8)
      { binst(); i+=2; sprintf(op1S,"#$%x",p[i+1]&31);
        eff(); strcpy(op2S,opS); return; }
  if (hibyte==14) { strcpy(instS,"moves"); i+=2;
                    if (p[i]&128) opS[0]='a'; else opS[0]='d';
                    opS[1] = 48 + ((p[i] & 112) >> 4);
                    opS[2] = '\0';
                    wp=(short *)&p[i];
                    if ((*wp)&2048)
                       { strcpy(op1S,opS); sizeff(); strcpy(op2S,opS); }
                    else {strcpy(op2S,opS); sizeff(); strcpy(op1S,opS); }
                    return;
                  }
  switch (hibyte)
    { case 0: strcpy(instS,"ori"); break;
      case 2: strcpy(instS,"andi"); break;
      case 4: strcpy(instS,"subi"); break;
      case 6: strcpy(instS,"addi"); break;
      case 10: strcpy(instS,"eori"); break;
      case 12: strcpy(instS,"cmpi");
    }
  switch (L76)
    { case 0: sprintf(op1S,"#$%x",p[i+3]&255); break;
      case 1: wp=(short *)&p[i+2]; sprintf(op1S,"#$%x",*wp); break;
      case 2: i+=2; lp=(long *)&p[i]; sprintf(op1S,"#$%lx",*lp);
    }
    i+=2; sizeff();
    if (mode==7 && reg==4) { i-=2; if (!L76) { strcpy(op2S,"ccr"); return; }
    else { strcpy(op2S,"sr"); return; }
    }  /* end if (mode==7 etc */
    strcpy(op2S,opS);
}

void
op0000xxx1()
{ if ((lobyte & 56)==8) { movep();return;}
  binst();
  dreg();
  strcpy(op1S,reg1S);
  eff();
  strcpy(op2S,opS);
}

void
op0000()
{
  if (hibyte&1) op0000xxx1(); else op0000xxx0();
}

void
op0001()
{ strcpy(instS,"move.b"); size=0; move();
}

void
op0010()
{ size=2; move();
}

void
op0011()
{ size=1; move();
}

void
op01001000()
{ if (!L76) {strcpy(instS,"nbcd"); eff(); strcpy(op1S,opS); return; }
  if ((L76==1) && (!(lobyte & 56))) strcpy(instS,"swap");
  else strcpy(instS,"pea");
  if (L76==1) { eff(); strcpy(op1S,opS); return; }
  if (!(lobyte&56)) { strcpy(instS,"ext");
                      if (L76==2) strcat(instS,".w");
                      else if (L76==3) strcat(instS,".l");
                      op1S[0]='d'; op1S[1]=48+(lobyte&7);
                      op1S[2]='\0'; return; }
  movem();
}

void
op01001010()
{ if (lobyte==252) { strcpy(instS,"illegal"); return; }
  if (L76==3) { strcpy(instS,"tas"); eff(); strcpy(op1S,opS); return; }
  strcpy(instS,"tst"); sizeff(); strcpy(op1S,opS);
}

void
op0100xxx0()
   {
    switch (lonib)
       {case 0:
            if (L76==3)
               {strcpy(instS,"move");
                strcpy(op1S,"sr");
                eff();
                strcpy(op2S,opS);
                }
              else 
               {strcpy(instS,"negx");
                sizeff();
                strcpy(op1S,opS);
                }
            return;
        case 2:
            if (L76==3)
               {strcpy(instS,"move");
                strcpy(op1S,"ccr");
                eff();
                strcpy(op2S,opS);
                }
              else
               {strcpy(instS,"clr");
                sizeff();
                strcpy(op1S,opS);
                }
            return;
        case 4:
            if (L76==3)
               {strcpy(instS,"move");
                eff();
                strcpy(op1S,opS);
                strcpy(op2S,"ccr");
                }
              else
               {strcpy(instS,"neg");
                sizeff();
                strcpy(op1S,opS);
                }
            return;
        case 6:
            if (L76==3)
               {strcpy(instS,"move");
                eff();
                strcpy(op1S,opS);
                strcpy(op2S,"sr");
                }
              else
               {strcpy(instS,"not");
                sizeff();
                strcpy(op1S,opS);
                }
            return;
        case 8:
            op01001000();
            return;
        case 10: 
            op01001010();
            return;
        case 12:
            movem();
            return;
        }
    switch (lobyte & 0xF0)
       {case 64:
            strcpy(instS,"trap");
            sprintf(op1S,"#$%x",lobyte&15);
            return;
        case 80:
            sprintf(op1S,"a%d",lobyte & 7);
            if (lobyte & 8)
                strcpy(instS,"unlk");
              else 
               {strcpy(instS,"link");
                i+=2;
                wp=(short *)&p[i];
                sprintf(op2S,"#$%x",*wp);
                }
            return;
        case 96:
            strcpy(instS,"move");
            sprintf(opS,"a%d",lobyte & 7);
            if (lobyte & 8)
               {strcpy(op1S,"usp");
                strcpy(op2S,opS);
                }
              else
               {strcpy(op1S,opS);
                strcpy(op2S,"usp");
                }
            return;
        }
    switch (lobyte)
       {case 112:
            strcpy(instS,"reset");
            return;
      case 113: strcpy(instS,"nop");
            return;
      case 114: strcpy(instS,"stop"); wp=(short *)&p[i+2];
                sprintf(op1S,"#$%x",*wp); i+=2;
            return;
      case 115: strcpy(instS,"rte"); break;
            return;
      case 116: strcpy(instS,"rtd"); i+=2; wp=(short *)&p[i];
                sprintf(op1S,"#$%x",*wp);
            return;
      case 117: strcpy(instS,"rts");
            return;
      case 118: strcpy(instS,"trapv");
            return;
      case 119: strcpy(instS,"rtr");
            return;
      case 122: strcpy(instS,"movec"); i+=2; movec();
                strcpy(op2S,opS);
            return;
      case 123: strcpy(instS,"movec"); i+=2; movec(); strcpy(op2S,op1S);
                strcpy(op1S,opS);
            return;
    }
    if (L76==2)
       {strcpy(instS,"jsr");
        eff();
        strcpy(op1S,opS);
        }
      else if (L76==3)
       {strcpy(instS,"jmp");
        eff();
        strcpy(op1S,opS);
        }
      else
        opinvalid();
    }

void
op0100xxx1()
   {if (L76==2)
       {strcpy(instS,"chk");
        dreg();
        }
      else if (L76==3)
       {strcpy(instS,"lea");
        areg();
        }
      else
        opinvalid();
    eff();
    strcpy(op1S,opS);
    strcpy(op2S,reg1S);
    }

void
op0100()
{ if (hibyte & 1) op0100xxx1(); else op0100xxx0();
}

void
op0101()
{ int quick;
  if (L76==3) { strcpy(instS,ccS[lonib]);
     if ((lobyte&56)==8) { dbcc(); return; }
     else { strcpy(opS,"s"); strcat(opS,instS); strcpy(instS,opS);
            eff(); strcpy(op1S,opS); return; }
  }
  if (lonib & 1) strcpy(instS,"subq"); else strcpy(instS,"addq");
  sizeff(); strcpy(op2S,opS);
  quick=(lonib & 14) >> 1;
  if (!quick) quick=8;
  op1S[0]='#'; op1S[1]=48+quick; op1S[2]='\0';
}

void
op0110()
{ if (!lonib) strcpy(instS,"bra");
  else if (lonib==1) strcpy(instS,"bsr");
  else { strcpy(instS,"b"); strcat(instS,ccS[lonib]);}
  if (!lobyte) { i+=2; strcat(instS,".w"); figurelabel();
                 sprintf(op1S,"%d%s",*wp,opS); return; }
  strcat(instS,".s");
  sprintf(op1S,"%-5d ($%lx)",p[i+1],iold + 2 + p[i+1]);
}

void
op0111()
   {strcpy(instS,"moveq"); 
    sprintf(op1S,"#%d",p[i+1]);
    dreg(); 
    strcpy(op2S,reg1S);
    }

void
op1000()
{ if (L76==3) { if (hibyte & 1) strcpy(instS,"divs");
                else strcpy(instS,"divu");
                size=1; dreg(); eff(); strcpy(op1S,opS);
                strcpy(op2S, reg1S); return; }
  if (hibyte & 1) { if (!(lobyte & 48)) { strcpy(instS,"sbcd"); dreg();
                       if (lobyte & 8) { sprintf(op1S,"-(a%d)",lobyte & 7);
                                         sprintf(op2S,"-(a%d)",reg1); }
                       else { sprintf(op1S,"d%d",lobyte & 7);
                              strcpy(op2S,reg1S); }
                                         }
                    else { strcpy(instS,"or"); dreg(); sizeff();
                           strcpy(op1S,reg1S); strcpy(op2S,opS); }
                   }
   else { strcpy(instS,"or"); dreg(); sizeff();
          strcpy(op1S,opS); strcpy(op2S,reg1S); }
}

void
op1001()
{ if (L76==3) { if (lonib & 1) { strcpy(instS,"suba.l"); size=2; }
                else {strcpy(instS,"suba.w"); size=1; }
      areg(); eff(); strcpy(op1S,opS); strcpy(op2S,reg1S); return;  }
  if (!(lonib & 1)) { strcpy(instS,"sub"); dreg(); sizeff();
                      strcpy(op1S,opS); strcpy(op2S,reg1S); }

  if (lonib & 1) { if (!(lobyte & 48)) { strcpy(instS,"subx");
                                         sizef(); dreg();
                       if (lobyte & 8) { sprintf(op1S,"-(a%d)",lobyte & 7);
                                sprintf(op2S,"-(a%d)",reg1); }
                     else { sprintf(op1S,"d%d",lobyte & 7);
                            strcpy(op2S,reg1S); }
                    }
                   else { strcpy(instS,"sub"); sizeff(); dreg();
                         strcpy(op1S,reg1S); strcpy(op2S,opS); }
  }
}

void
op1011()
{ if (L76==3) { strcpy(instS,"cmpa");
      if (lonib & 1) { size=2; strcat(instS,".l"); }
      else { size=1; strcat(instS,".w"); }
      areg(); eff(); strcpy(op1S,opS); strcpy(op2S,reg1S); return; }
  if (lonib & 1) { mode=(lobyte & 56) >> 3;
                   if (mode==1) { strcpy(instS,"cmpm"); sizeff(); dreg();
                     sprintf(op1S,"(%s)+",opS);
                     sprintf(op2S,"(a%d)+",reg1); }
                   else { strcpy(instS,"eor"); sizeff(); dreg();
                          strcpy(op1S,reg1S); strcpy(op2S,opS); }
                  }
  else { strcpy(instS,"cmp"); sizeff(); dreg();
         strcpy(op1S,opS); strcpy(op2S,reg1S); }
}

void
op1100()
{ if (L76==3)  {
    if (lonib & 1) strcpy(instS,"muls"); else strcpy(instS,"mulu");
    size=1; dreg(); eff(); strcpy(op1S,opS); strcpy(op2S,reg1S); return; }
  if (!(lonib & 1)) { strcpy(instS,"and"); dreg(); sizeff();
                      strcpy(op1S,opS); strcpy(op2S,reg1S); return; }
  if (!(lobyte & 48)) {
    if (!L76) { strcpy(instS,"abcd"); dreg(); eff();
      if (mode==1) { sprintf(op1S,"-(%s)",opS);
                     sprintf(op2S,"-(a%d)",reg1); return; }
      else { strcpy(op1S,opS); strcpy(op2S,reg1S); return; }
    }
    strcpy(instS,"exg"); eff(); dreg();
    if (L76==2) { strcpy(op1S,reg1S); strcpy(op2S,opS); return; }
    if (mode==1) { strcpy(op1S,opS); sprintf(op2S,"a%d",reg1); }
    else { strcpy(op1S,opS); strcpy(op2S,reg1S); }
    return;
  }
  strcpy(instS,"and"); dreg(); sizeff();
  strcpy(op1S,reg1S); strcpy(op2S,opS);
}

void
op1101()
{ if (L76==3) { strcpy(instS,"adda");
     if (lonib & 1) { size=2; strcat(instS,".l"); }
     else { size=1; strcat(instS,".w");  }
     areg(); eff(); strcpy(op1S,opS); strcpy(op2S,reg1S); return;
     }
  if (!(lonib & 1)) { strcpy(instS,"add"); dreg(); sizeff();
                    strcpy(op1S,opS); strcpy(op2S,reg1S); return; }
  if (lobyte & 48) {strcpy(instS,"add"); sizeff(); dreg();
                    strcpy(op1S,reg1S); strcpy(op2S,opS); return; }
  strcpy(instS,"addx"); sizeff(); dreg();
  if (mode==1) { sprintf(op1S,"-(%s)",opS); sprintf(op2S,"-(a%d)",reg1); }
  else { strcpy(op1S,opS); strcpy(op2S,reg1S); }
}

void
op1110()
{ int sh;
  if (L76==3) { sprintf(instS,"%s.w",shiftS[lonib]); eff();
                strcpy(op1S,opS); return; }
  dreg(); sprintf(op2S,"d%d",lobyte & 7);
  sh= ((lobyte & 24) >> 2) + (lonib & 1);
  strcpy(instS,shiftS[sh]);
  sizef();
  if (lobyte & 32) { strcpy(op1S,reg1S); return; }
  if (!reg1) reg1=8;
  sprintf(op1S,"#$%x",reg1);
}

voidfun opxxxx[16] =
   {op0000,op0001,op0010,op0011,
    op0100,op0101,op0110,op0111,
    op1000,op1001,opinvalid,op1011,
    op1100,op1101,op1110,opinvalid
    };

void
disass(length,fptr)
    int  length;
    FILE *fptr;
   {
    unsigned int hinib;

    i = 0;
    p = calloc(length,sizeof(long));
    if(p==NULL)
       {my_printf("malloc failed\n");
        exit(20);
        }
    my_fread(p,length*sizeof(long),fptr);

    while (i<length*sizeof(long))
       { /* main loop */
        iold=i;
        hibyte=p[i]&255;
        lobyte=p[i+1]&255;
        L76=lobyte>>6&15;
        hinib=hibyte>>4;
        lonib=hibyte&15;
        /* initialize strings */
        instS[0]='\0';
        op1S[0]='\0';
        op2S[0]='\0';
        /* Call the function selected by the hi nibble */
        (*opxxxx[hinib])();
        /* If there were two ops then concatenate them */
        if (strlen(op1S))
            if (strlen(op2S))
               {strcpy(opS,",");
                strcat(opS,op2S);
                strcat(op1S,opS);
                }
        i+=2;
        my_printf("  %4lx:  %-7s  %-24s",iold,instS,op1S);
        genasc();
        genobj();
        my_printf("%-16s  %s\n",objS,ascS);
        }
    /* Now free the storage we loaded the code into */
    free(p);
    }

#ifdef NEED_MAIN
main(argc, argv)
int argc;
char **argv;
{  register long  maxi=0, line=0;
   register char ch;
   FILE *fromfile, *tofile;
   unsigned int hinib;
   char *fromname, *toname, outname[40];

   if (argc < 2 || argc > 3)
     {
       printf("Useage: disass fromfile <tofile>\n");
       printf("If tofile omitted, output will be directed to monitor.\n");
       printf("If tofile specified, .asm will be appended to tofile.\n");
       printf("\nWarning!! Output file may be about 13 times as big as \n");
       printf("input file. Make sure you have enough memory.\n");
       printf("Maximum input file size set for 20,000 bytes.\n");
       printf("For maximum speed, send output to ram:.\n");
       exit(4);
     }
  fromfile = fopen(argv[1], "r");
  if (fromfile == NULL )
     {
       printf("Can't open: %s\n", argv[1]);
       exit(4);
     }
  if (argc==3)
     { sprintf(outname,"%s.asm",argv[2]);
       tofile = fopen(outname, "w");
       if (tofile == NULL )
         { printf("Can't open: %s\n", argv[2]);
           exit(4); }
       printf("%s opened\n",argv[2]);
       fprintf(tofile,"PC\tINST\tOPERANDS\t\tASCII\t HEX\n");
     }
  printf("Reading %s\n",argv[1]);
  ch=fgetc(fromfile);
  while (!feof(fromfile)  && maxi<maxfile)
    {
      p[maxi++]=ch;
      ch=fgetc(fromfile);
    }

  printf("number of bytes loaded %ld\n\n",maxi);
  fclose( fromfile);  printf("Input file %s closed.\n\n",argv[1]);

    do {
        printf("Enter a starting PC (program counter) between 0 and %ld ",maxi-2);
        fflush(stdout);
        scanf("%ld",&i);
        }

  disass();

  if (argc==3)
    { fclose( tofile );
      printf("\nFinished.  Output file %s closed.\n",outname); }
  exit(0);
}
#endif
