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

#define FALSE  0
#define TRUE   1


void    mem_check();
char  * dis_ass(),
        take_char();
short   dummy;

void reset( code)
PM *code;
{
   code->PC = code->Me [0xFFFC] | code->Me [0xFFFD] << 8;

   code->Ac = 0x00;
   code->Xr = 0x00;
   code->Yr = 0x00;

   code->Ne = FALSE;    code->Ov = FALSE;    code->Br = TRUE;
   code->De = FALSE;    code->In = FALSE;    code->Ze = FALSE;
   code->Ca = FALSE;

   code->Er = FALSE;

   code->SP = 0xFF;

}


void
   ADC_imm(), ADC_zer(), ADC_zex(), ADC_abs(), ADC_abx(), ADC_aby(),
   ADC_inx(), ADC_iny(),
   AND_imm(), AND_zer(), AND_zex(), AND_abs(), AND_abx(), AND_aby(),
   AND_inx(), AND_iny(),
   ASL_acc(), ASL_zer(), ASL_zex(), ASL_abs(), ASL_abx(),
   BCC(),     BCS(),     BEQ(),
   BIT_zer(), BIT_abs(),
   BMI(),     BNE(),     BPL(),
   BRK(),
   BVC(),     BVS(),
   CLC(),     CLD(),     CLI(),     CLV(),
   CMP_imm(), CMP_zer(), CMP_zex(), CMP_abs(), CMP_abx(), CMP_aby(),
   CMP_inx(), CMP_iny(),
   CPX_imm(), CPX_zer(), CPX_abs(),
   CPY_imm(), CPY_zer(), CPY_abs(),
   DEC_zer(), DEC_zex(), DEC_abs(), DEC_abx(),
   DEX(),     DEY(),
   EOR_imm(), EOR_zer(), EOR_zex(), EOR_abs(), EOR_abx(), EOR_aby(),
   EOR_inx(), EOR_iny(),
   INC_zer(), INC_zex(), INC_abs(), INC_abx(),
   INX(),     INY(),
   JSR();

void JMP( code)
PM *code;
{
   unsigned short int address;

   address = abs_address( code);
   code->PC = address;
   mem_check( address, &dummy, code, Func_JMP);
}

void JMP_ind( code)
PM *code;
{

   unsigned short int  address;

   address = code->Me [code->Me [code->PC] |
                       code->Me [code->PC + 1] << 8]       |
             code->Me [(code->Me [code->PC] |
                       code->Me [code->PC + 1] << 8) + 1] << 8;

   code->PC = address;
   mem_check( address, &dummy, code, Func_JMP);
}

void
   LDA_imm(), LDA_zer(), LDA_zex(), LDA_abs(), LDA_abx(), LDA_aby(),
   LDA_inx(), LDA_iny(),
   LDX_imm(), LDX_zer(), LDX_zex(), LDX_abs(), LDX_aby(),
   LDY_imm(), LDY_zer(), LDY_zex(), LDY_abs(), LDY_abx(),
   LSR_acc(), LSR_zer(), LSR_zex(), LSR_abs(), LSR_abx();

void NOP( code)
PM *code;
{
   /* No operation */
}

void
   ORA_imm(), ORA_zer(), ORA_zex(), ORA_abs(), ORA_abx(), ORA_aby(),
   ORA_inx(), ORA_iny(),
   PHA(),     PHP(),     PLA(),     PLP(),
   ROL_acc(), ROL_zer(), ROL_zex(), ROL_abs(), ROL_abx(),
   ROR_acc(), ROR_zer(), ROR_zex(), ROR_abs(), ROR_abx(),
   RTI(),     RTS(),
   SBC_imm(), SBC_zer(), SBC_zex(), SBC_abs(), SBC_abx(), SBC_aby(),
   SBC_inx(), SBC_iny(),
   SEC(),     SED(),     SEI(),
   STA_zer(), STA_zex(), STA_abs(), STA_abx(), STA_aby(), STA_inx(),
   STA_iny(),
   STX_zer(), STX_zex(), STX_abs(),
   STY_zer(), STY_zex(), STY_abs(),
   TAX(),     TAY(),     TSX(),     TXA(),     TXS(),     TYA();

Debugg( code)
PM *code;
{
   short               steps;
   unsigned short int  current_PC;

   code->Qu = TRUE;
   code->Mo = Mode_SLOW;
   printf("\nInternal signal (DEBUGG)\n\n");

   current_PC = code->PC;
   code->PC -=0x10;
   while (code->PC < current_PC + 0x10)
   {
      if ( (code->PC > current_PC - 7) && (code->PC < current_PC + 3) )
      {
         if (code->PC == current_PC - 1)
            printf("%s <-           ; Debugg  ON\n", dis_ass( code, &steps) );
         else
            printf("%s\n", dis_ass( code, &steps) );
      }

      else
         dis_ass( code, &steps);

      code->PC += steps;
   }

   code->PC = current_PC - 1;
   printf("\n$%04x-   ", code->PC);
   reg_dump( code);
   printf("\n");

   code->PC = current_PC;
}

void none( code)
PM *code;
{
   short steps;   /* Dummy */

   code->PC--;
      printf("Can't Evaluate\n");
      printf("\n%s\n", dis_ass( code, &steps) );
   code->PC++;
   code->Er = TRUE;
   code->Qu = TRUE;  /* Quit of type ERROR */
}

void (*OP_code[])() = {
/*       00       01       02       03       04       05       06       07 */
/*       08       09       0A       0B       0C       0D       0E       0F */
/* 00 */ BRK,     none,    none,    none,    none,    ORA_zer, ASL_zer, none,
         PHP,     ORA_imm, ASL_acc, none,    none,    ORA_abs, ASL_abs, none,
/* 10 */ BPL,     ORA_iny, none,    none,    none,    ORA_zex, ASL_zex, none,
         CLC,     ORA_aby, none,    none,    none,    ORA_abx, ASL_abx, none,
/* 20 */ JSR,     AND_inx, none,    none,    BIT_zer, AND_zer, ROL_zer, none,
         PLP,     AND_imm, ROL_acc, none,    BIT_abs, AND_abs, ROL_abs, none,
/* 30 */ BMI,     AND_iny, none,    none,    none,    AND_zex, none,    none,
         SEC,     AND_aby, none,    none,    none,    AND_abx, ROL_abx, none,
/* 40 */ none,    EOR_inx, none,    none,    none,    EOR_zer, LSR_zer, none,
         PHA,     EOR_imm, LSR_acc, none,    JMP,     EOR_abs, LSR_abs, none,
/* 50 */ BVC,     EOR_iny, none,    none,    none,    EOR_zex, LSR_zex, none,
         CLI,     EOR_aby, none,    none,    none,    EOR_abx, LSR_abx, none,
/* 60 */ RTS,     ADC_inx, none,    none,    none,    ADC_zer, ROR_zer, none,
         PLA,     ADC_imm, ROR_acc, none,    JMP_ind, ADC_abs, ROR_abs, none,
/* 70 */ BVS,     ADC_iny, none,    none,    none,    ADC_zex, ROR_zex, none,
         SEI,     ADC_aby, none,    none,    none,    none,    ROR_abx, none,
/* 80 */ none,    STA_inx, none,    none,    STY_zer, STA_zer, STX_zer, none,
         DEY,     none,    TXA,     none,    STY_abs, STA_abs, STX_abs, none,
/* 90 */ BCC,     STA_iny, none,    none,    STY_zex, STA_zex, STX_zex, none,
         TYA,     STA_aby, TXS,     none,    none,    STA_abx, none,    none,
/* A0 */ LDY_imm, LDA_inx, LDX_imm, none,    LDY_zer, LDA_zer, LDX_zer, none,
         TAY,     LDA_imm, TAX,     none,    LDY_abs, LDA_abs, LDX_abs, none,
/* B0 */ BCS,     LDA_iny, none,    none,    LDY_zex, LDA_zex, LDX_zex, none,
         CLV,     LDA_aby, TSX,     none,    LDY_abx, LDA_abx, LDX_aby, none,
/* C0 */ CPY_imm, CMP_inx, none,    none,    CPY_zer, CMP_zer, DEC_zer, none,
         INY,     CMP_imm, DEX,     none,    CPY_abs, CMP_abs, DEC_abs, none,
/* D0 */ BNE,     CMP_iny, none,    none,    none,    none,    DEC_zex, none,
         CLD,     CMP_aby, none,    none,    none,    CMP_abx, DEC_abx, none,
/* E0 */ CPX_imm, SBC_inx, none,    none,    CPX_zer, SBC_zer, INC_zer, none,
         INX,     SBC_imm, NOP,     none,    CPX_abs, SBC_abs, INC_abs, none,
/* F0 */ BEQ,     SBC_iny, none,    none,    none,    SBC_zex, INC_zex, none,
         none,    SBC_aby, none,    none,    none,    SBC_abx, INC_abx, Debugg
};

tracing( code)
PM *code;
{
   short tecken;

   if (code->Tl == 0,1)
   {
      char  buffer [256];
      short steps;   /* Dummy */

      reg_dump( code);
/*
      tecken = getc( stdin);

      printf("%d->\n", code->Tl);
*/
tecken = 0xFF;
      strcpy( buffer, dis_ass( code, &steps) );
      strcat( buffer, "                    " );
      buffer [37] = NULL;
      printf( buffer);
   }

   if (code->Me [code->PC] == 0x20)
      code->Tl += 2;

   if (code->Me [code->PC] == 0x60)
      code->Tl -= 2;

   if (code->Tl < code->SP,0) /*qq*/
   {
      printf("Back from Trace.\n");
      code->Tl = code->SP;
      break_meny( code);
   }

   if (tecken == '\b')
      code->Tl --;

   if (toupper( tecken) == 'N')
      code->Tl ++;

   if ( toupper( tecken) == 'Q')
   {
      printf("Quit ?\n");
      code->Er = TRUE;
   }

   if (tecken == '\233')
      code->Tr = FALSE;

   if (toupper( tecken) == 'M')
      code->PC = 0xFF65;
}

break_meny( code)
PM    * code;
{
   short tecken,
         action;

   code->Qu = FALSE;

   action = FALSE;
   while (!action)
   {
      printf("\n:");
      tecken = getc( stdin);

      switch( toupper( tecken) )
      {
         case 'M':
            printf(" Monitor.\n");
            code->PC = 0xFF65;
            code->Me [0x0036] = 0xF0;
            code->Me [0x0037] = 0xFD;
            code->Me [0x0038] = 0x1B;
            code->Me [0x0039] = 0xFD;
            refresh();
            action = TRUE;
            break;

         case 'Q':
            printf(" Quit.\n");
            code->Ex = TRUE;
            code->Qu = TRUE;
            action = TRUE;
            break;

         case 'C':
            printf(" Continue.\n");
            action = TRUE;
            break;

         case 'T':
            printf(" Trace ON\n");
            code->Tr = TRUE;
            code->Tl = code->SP;
            action = TRUE;
            break;

         case 'O':
            printf(" Trace OFF\n");
            code->Tr = FALSE;
            action = TRUE;
            break;

         case 'F':
            printf(" Fast.\n");
            code->Mo = Mode_FAST;
            code->Qu = TRUE;
            action = TRUE;
            break;

         case 'S':
            printf(" Slow.\n");
            code->Mo = Mode_SLOW;
            code->Qu = TRUE;
            action = TRUE;
            break;

         default:
            printf(" M, Q, C, T, O, F, S");
            break;

      }  /* End of switch (tecken) */
   }  /* End of while (!action) */

}

quit_check( code)
PM *code;
{
   if (code->Qu)
      /* Let it pass */
      return;

   if (char_check() )
   {
      short tecken;

      if ( (tecken = take_char() ) == '\233')
      {
         short tecken_2;

         tecken_2 = take_char();
         if (tecken_2 == '\233')
            code->Qu = TRUE;
         else
            char_take_back( tecken_2);
      }
      else
         char_take_back( tecken);
   }
}

void slow_cpu( code)
PM *code;
{
   char tecken;

   do  /* Until code->Qu == TRUE */
   {
      if (code->Qu)
         break_meny( code);

      else
      {
code->Br = TRUE;
         (*OP_code [code->Me [(code->PC)++] ])( code);

         /* Check Esc-Esc break */
         quit_check( code);
      }

      if (code->Ex)
         break;

      if (code->Tr)
         tracing( code);

   }  while (!code->Qu);

}

void fast_cpu( code)
PM *code;
{

   while (
code->Br = TRUE,
          !code->Qu)
      (*OP_code [code->Me [(code->PC)++] ])( code);

}



