#include <cpu_prog_model.h>
#include <stdio.h>

#define FALSE  0
#define TRUE   1

char *Mnemonic [] =
{
/*             00               01                02                03     */
/*             04               05                06                07     */
/*             08               09                0A                0B     */
/*             0C               0D                0E                0F     */
/*
/* 00 */  "\001BRK",        "\000???",        "\000???",        "\000???",
/*    */  "\000???",        "\003ORA",        "\003ASL",        "\000???",
/*    */  "\001PHP",        "\002ORA",        "\015ASL",        "\000???",
/*    */  "\000???",        "\006ORA",        "\006ASL",        "\000???",
/* 10 */  "\014BPL",        "\012ORA",        "\000???",        "\000???",
/*    */  "\000???",        "\004ORA",        "\004ASL",        "\000???",
/*    */  "\001CLC",        "\006ORA",        "\000???",        "\000???",
/*    */  "\000???",        "\007ORA",        "\007ASL",        "\000???",
/* 20 */  "\006JSR",        "\011AND",        "\000???",        "\000???",
/*    */  "\003BIT",        "\003AND",        "\003ROL",        "\000???",
/*    */  "\001PLP",        "\002AND",        "\015ROL",        "\000???",
/*    */  "\006BIT",        "\006AND",        "\006ROL",        "\000???",
/* 30 */  "\014BMI",        "\000???",        "\000???",        "\000???",
/*    */  "\000???",        "\004AND",        "\004ROL",        "\000???",
/*    */  "\001SEC",        "\010AND",        "\000???",        "\000???",
/*    */  "\000???",        "\007AND",        "\007ROL",        "\000???",
/* 40 */  "\001RTI",        "\011EOR",        "\000???",        "\000???",
/*    */  "\000???",        "\003EOR",        "\003LSR",        "\000???",
/*    */  "\001PHA",        "\002EOR",        "\015LSR",        "\000???",
/*    */  "\006JMP",        "\006EOR",        "\006LSR",        "\000???",
/* 50 */  "\014BVC",        "\012EOR",        "\000???",        "\000???",
/*    */  "\000???",        "\004EOR",        "\004LSR",        "\000???",
/*    */  "\001CLI",        "\010EOR",        "\000???",        "\000???",
/*    */  "\000???",        "\007EOR",        "\007LSR",        "\000???",
/* 60 */  "\001RTS",        "\000???",        "\000???",        "\000???",
/*    */  "\000???",        "\003ADC",        "\003ROR",        "\000???",
/*    */  "\001PLA",        "\002ADC",        "\015ROR",        "\000???",
/*    */  "\013JMP",        "\006ADC",        "\006ROR",        "\000???",
/* 70 */  "\014BVS",        "\012ADC",        "\000???",        "\000???",
/*    */  "\000???",        "\004ADC",        "\004ROR",        "\000???",
/*    */  "\001SEI",        "\000???",        "\000???",        "\000???",
/*    */  "\000???",        "\000???",        "\007ROR",        "\000???",
/* 80 */  "\000???",        "\000???",        "\000???",        "\000???",
/*    */  "\003STY",        "\003STA",        "\003STX",        "\000???",
/*    */  "\001DEY",        "\000???",        "\001TXA",        "\000???",
/*    */  "\006STY",        "\006STA",        "\006STX",        "\000???",
/* 90 */  "\014BCC",        "\012STA",        "\000???",        "\000???",
/*    */  "\004STY",        "\004STA",        "\005STX",        "\000???",
/*    */  "\001TYA",        "\010STA",        "\001TXS",        "\000???",
/*    */  "\000???",        "\007STA",        "\000???",        "\000???",
/* A0 */  "\002LDY",        "\011LDA",        "\002LDX",        "\000???",
/*    */  "\003LDY",        "\003LDA",        "\003LDX",        "\000???",
/*    */  "\001TAY",        "\002LDA",        "\001TAX",        "\001???",
/*    */  "\006LDY",        "\006LDA",        "\006LDX",        "\000???",
/* B0 */  "\014BCS",        "\012LDA",        "\000???",        "\000???",
/*    */  "\004LDY",        "\004LDA",        "\005LDX",        "\000???",
/*    */  "\001CLV",        "\010LDA",        "\001TSX",        "\000???",
/*    */  "\007LDY",        "\007LDA",        "\010LDX",        "\000???",
/* C0 */  "\002CPY",        "\000???",        "\000???",        "\000???",
/*    */  "\003CPY",        "\003CMP",        "\003DEC",        "\000???",
/*    */  "\001INY",        "\002CMP",        "\001DEX",        "\000???",
/*    */  "\006CPY",        "\006CMP",        "\006DEC",        "\000???",
/* D0 */  "\014BNE",        "\012CMP",        "\000???",        "\000???",
/*    */  "\000???",        "\004CMP",        "\004DEC",        "\000???",
/*    */  "\001CLD",        "\010CMP",        "\000???",        "\000???",
/*    */  "\000???",        "\007CMP",        "\007DEC",        "\000???",
/* E0 */  "\002CPX",        "\000???",        "\000???",        "\000???",
/*    */  "\003CPX",        "\003SBC",        "\003INC",        "\000???",
/*    */  "\001INX",        "\002SBC",        "\001NOP",        "\000???",
/*    */  "\006CPX",        "\006SBC",        "\006INC",        "\000???",
/* F0 */  "\014BEQ",        "\012SBC",        "\000???",        "\000???",
/*    */  "\000???",        "\004SBC",        "\004INC",        "\000???",
/*    */  "\001SED",        "\000???",        "\000???",        "\000???",
/*    */  "\000???",        "\007SBC",        "\007INC",        "\001DBG"
};

char *jumpers_FDxx [] =
{
/* FD00 */   "", "", "", "", "", "", "", "", "", "", "", "",
/* FD0C */   "      ; $FD0C = RdKey",
/* FD0D */   "", "", "",
/* FD10 */   "", "", "", "", "", "", "", "", "", "", "",
/* FD1B */   "      ; $FD1B = KeyIn",
/* FD1C */   "", "", "", "",
/* FD20 */   "",
/* FD21 */   "      ; $FD21 = KeyIn2",
/* FD22 */   "", "", "", "", "", "", "", "", "", "", "", "", "",
/* FD2F */   "      ; $FD2F = Esc",
/* FD30 */   "", "", "", "", "",
/* FD35 */   "      ; $FD35 = RdChar",
/* FD36 */   "", "", "", "", "", "", "",
/* FD3D */   "      ; $FD3D = NotCr",
/* FD3E */   "", "",
/* FD40 */   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
/* FD50 */   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
/* FD5F */   "      ; $FD5F = NotCr1",
/* FD60 */   "", "",
/* FD62 */   "      ; $FD62 = Cancel",
/* FD63 */   "", "", "", "",
/* FD67 */   "      ; $FD67 = GetLnZ",
/* FD68 */   "", "",
/* FD6A */   "      ; $FD6A = GetLn",
/* FD6B */   "", "", "", "", "",
/* FD70 */   "",
/* FD71 */   "      ; $FD71 = BckSpc",
/* FD72 */   "", "", "",
/* FD75 */   "      ; $FD75 = NxtChar",
/* FD76 */   "", "", "", "", "", "", "", "",
/* FD7E */   "      ; $FD7E = CapTst",
/* FD7F */   "",
/* FD80 */   "", "", "", "",
/* FD84 */   "      ; $FD84 = AddInp",
/* FD85 */   "", "", "", "", "", "", "", "", "",
/* FD8E */   "      ; $FD8E = CrOut",
/* FD8F */   "",
/* FD90 */   "", "",
/* FD92 */   "      ; $FD92 = Pra1",
/* FD93 */   "", "", "",
/* FD96 */   "      ; $FD96 = PrYX2",
/* FD97 */   "", "", "", "", "", "", "", "", "",
/* FDA0 */   "", "", "",
/* FDA3 */   "      ; $FDA3 = XAm8",
/* FDA4 */   "", "", "", "", "", "", "", "", "",
/* FDAD */   "      ; $FDAD = Mod8Chk",
/* FDAE */   "", "",
/* FDB0 */   "", "", "",
/* FDB3 */   "      ; $FDB3 = Xam",
/* FDB4 */   "", "",
/* FDB6 */   "      ; $FDB6 = DataOut",
/* FDB7 */   "", "", "", "", "", "", "", "", "",
/* FDC0 */   "", "", "", "", "",
/* FDC5 */   "      ; $FDC5 = Rts4c",
/* FDC6 */   "      ; $FDC6 = XAmpm",
/* FDC7 */   "", "", "", "", "", "", "", "", "",
/* FDD0 */   "",
/* FDD1 */   "      ; $FDD1 = Add",
/* FDD2 */   "", "", "", "", "", "", "", "",
/* FDDA */   "      ; $FDDA = PrByte",
/* FDDB */   "", "", "", "", "",
/* FDE0 */   "", "", "",
/* FDE3 */   "      ; $FDE3 = PrHex",
/* FDE4 */   "",
/* FDE5 */   "      ; $FDE5 = PrHexZ",
/* FDE6 */   "", "", "", "", "", "", "",
/* FDED */   "      ; $FDED = COut",
/* FDEE */   "", "",
/* FDF0 */   "      ; $FDF0 = COut1",
/* FDF1 */   "", "", "", "", "",
/* FDF6 */   "      ; $FDF6 = COutZ",
/* FDF7 */   "", "", "", "", "", "", "", "", ""
};

char *jump_check( address)
unsigned short int address;
{
   static char out_string [256];

   sprintf( out_string, "$%04x", address);
   if ( ((address >> 8) == 0xFD) && (*jumpers_FDxx [address & 0xFF]) )
      strcat( out_string, jumpers_FDxx [address & 0xFF]);

   return (out_string);
}

char  * dis_ass( code, length)
PM    * code;
short * length;
{
   char        * string,
                 temp_buffer [256];
   static char   out_buffer  [256];

   unsigned short int value;
   static short int   DFB_flag = FALSE;

   short  position,
          temp_pos,
          dfb_str_flag;

   sprintf( out_buffer, "$%04x-   ", code->PC );
   string = Mnemonic [code->Me [code->PC] ];

   if (DFB_flag)
      *string = '\000';

   switch (*string)
   {
      case NONE:   /* \000 */
         DFB_flag = TRUE;
         sprintf( out_buffer + strlen( out_buffer) , "            DFB   ");
         for (position = 0; (position < 2) &
                            ( (code->Me [code->PC + position] & 0x7F) >=
                                                         0x20);  position++)
            /* Take onle thre realy letters to the buffer */
            temp_buffer [position] = code->Me [code->PC + position];

         /* Don't forget the last character */
         temp_buffer [position++] = code->Me [code->PC + position];

         /* Check the first letter */
         dfb_str_flag = FALSE;
         if ( ((*temp_buffer & 0x7F) > 0x20) && (*temp_buffer != 0xFF) )
         {
            /* This is a string */
            strcat( out_buffer + 27, "\"");   /* Print  " */
            dfb_str_flag = TRUE;
         }

         for (temp_pos = 0; temp_pos < position; temp_pos ++)
         {
            char tecken;     /* pos 9 */
            sprintf( out_buffer + 9 + temp_pos * 3, "%02x ",
                                                    temp_buffer [temp_pos] );
            out_buffer [9 + (temp_pos + 1) * 3] = ' ';

            tecken = temp_buffer [temp_pos];
            if (tecken == 0)
            {
               if (dfb_str_flag)
                  strcat( out_buffer, "\", 0");
               else
                  strcat( out_buffer, "0");
               dfb_str_flag = FALSE;
               DFB_flag = FALSE;
               break;
            }

            if ( ((tecken & 0x7F) < 0x20) || (tecken == 0xFF) )
            {
               if (dfb_str_flag)
                  sprintf( out_buffer + strlen( out_buffer), "\", $%02x",
                                                                  tecken  );
               else
                  sprintf( out_buffer + strlen( out_buffer), "$%02x", tecken);

               dfb_str_flag = FALSE;
               DFB_flag = FALSE;
               break;
            }

            if ( (tecken == '\\') || (tecken == '\"') )
               strcat( out_buffer, "\\");

            sprintf( out_buffer + strlen( out_buffer), "%c", tecken);
         }

         if (dfb_str_flag)
            strcat( out_buffer, "\"");

         *length = position;
         break;

      case Implied:   /* \001 */
         sprintf( out_buffer + strlen( out_buffer), "%02x          ",
                                                    code->Me [code->PC]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         *length = 1;
         break;

      case Immediate:   /* \002 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer),
                                       "   #$%02x",
                                       code->Me [code->PC + 1]);

         if ( ((code->Me [code->PC + 1] & 0x7F) >= 0x20) &&
              ((code->Me [code->PC + 1] & 0x7F) != 0x7F)     )
            sprintf( out_buffer + strlen( out_buffer),
                            "       ;   $%02x = '%c'",
                              code->Me [code->PC + 1],
                              code->Me [code->PC + 1]  );

         *length = 2;
         break;

      case Zero_page:   /* \003 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer),
                                        "   $%02x",
                                        code->Me [code->PC + 1]);

         *length = 2;
         break;

      case Zero_page_X:   /* \004 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   $%02x,X",
                                         code->Me [code->PC + 1]  );

         *length = 2;
         break;

      case Zero_page_Y:   /* \005 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   $%02x,Y",
                                         code->Me [code->PC + 1]  );

         *length = 2;
         break;

      case Absolute:    /* \006 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x %02x    ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1],
                                                    code->Me [code->PC + 2] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   %s",
                  jump_check( code->Me [code->PC + 1] |
                              code->Me [code->PC + 2] << 8) );
         *length = 3;
         break;

      case Absolute_X:   /* \007 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x %02x    ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1],
                                                    code->Me [code->PC + 2] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer),
                  "   %s,X", jump_check( code->Me [code->PC + 1] |
                                         code->Me [code->PC + 2] << 8) );
         *length = 3;
         break;

      case Absolute_Y:   /* \010 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x %02x    ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1],
                                                    code->Me [code->PC + 2] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer),
                  "   %s,Y", jump_check( code->Me [code->PC + 1] |
                                         code->Me [code->PC + 2] << 8) );
         *length = 3;
         break;

      case Indirect_Y:   /* \012 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   (%s),Y",
                  jump_check( code->Me [code->Me [code->PC + 1] ] |
                              code->Me [code->Me [code->PC + 1] + 1] << 8) );
         *length = 2;
         break;

      case Indirect_X:   /* \011 */
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   (%s)",
                  jump_check( code->Me [code->Me [code->PC + 1] +
                                        code->Xr                  ] |
                              code->Me [code->Me [code->PC + 1] +
                                        code->Xr + 1              ] << 8) );
         *length = 2;
         break;

      case Indirect:
         sprintf( out_buffer + strlen( out_buffer), "%02x %02x %02x    ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1],
                                                    code->Me [code->PC + 2] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   %s",
                  jump_check(
                     code->Me [code->Me [code->PC + 1] |
                               code->Me [code->PC + 2] << 8] |
                     code->Me [(code->Me [code->PC + 1] |
                                code->Me [code->PC + 2] << 8) + 1] << 8) );

         *length = 3;
         break;

      case Relative:
         value = code->Me [code->PC + 1];
         if (value >= 0x80)
            value |= (-1 ^ 0xFF);
         value += (code->PC + 2);
         value &= 0xFFFF;

         sprintf( out_buffer + strlen( out_buffer), "%02x %02x       ",
                                                    code->Me [code->PC],
                                                    code->Me [code->PC + 1]);
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         sprintf( out_buffer + strlen( out_buffer), "   %s",
                                                    jump_check( value) );
         *length = 2;
         break;

      case Accumulator:   /* \015 */
         sprintf( out_buffer + strlen( out_buffer), "%02x          ",
                                                    code->Me [code->PC] );
         sprintf( out_buffer + strlen( out_buffer), string + 1);
         strcat( out_buffer, "   A");
         *length = 1;
         break;

      default:
printf("Bugg '%s'  case %d\n", string + 1, *string);
         printf( "Internal Error!\n");
         exit (-1);
   }

   return (out_buffer);
}



