/*====================================================================
  opcodes_dd_fd.c -> This file executes the DD/FD PREFIX opcodes.

  The DD prefix "creates" some new instructions by changing HL to IX
  on the opcode defined by the next byte on memory.

  The FD prefix "creates" some new instructions by changing HL to IY
  on the opcode defined by the next byte on memory.

  Change the REGISTER variable to IX or HY before including this file.
  Something like:

        #define REGISTER  regs->IX
            #include "op_dd_fd.c"
        #undef  REGISTER

 On this code, this REGISTER variable is used as REGISTER.W or
 REGISTER.B.h and REGISTER.B.l ...

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 Copyright (c) 2000 Santiago Romero Iglesias.
 Email: sromero@escomposlinux.org
 =====================================================================*/

/* 8 clock cycles minimum = DD opcode = FD opcode = 4 + 4 */

#define REG  REGISTER.W
#define REGL REGISTER.B.l
#define REGH REGISTER.B.h

opcode = Z80ReadMem (r_PC);
r_PC++;

switch (opcode)
  {
  case ADD_IXY_BC:
    ADD_WORD (REG, r_BC);
    AddCycles (4 + 4 + 7);
    break;
  case ADD_IXY_DE:
    ADD_WORD (REG, r_DE);
    AddCycles (4 + 4 + 7);
    break;
  case ADD_IXY_SP:
    ADD_WORD (REG, r_SP);
    AddCycles (4 + 4 + 7);
    break;
  case ADD_IXY_IXY:
    ADD_WORD (REG, REG);
    AddCycles (4 + 4 + 7);
    break;
  case DEC_IXY:
    REG--;
    AddCycles (4 + 4 + 2);
    break;
  case INC_IXY:
    REG++;
    AddCycles (4 + 4);
    break;

  case JP_IXY:
    r_PC = REG;
    AddCycles (4 + 4);
    break;
  case LD_SP_IXY:
    r_SP = REG;
    AddCycles (4 + 4 + 2);
    break;

  case PUSH_IXY:
    PUSH_IXYr ();
    AddCycles (4 + 4 + 3 + 3 + 1);
    break;
  case POP_IXY:
    POP_IXYr ();
    AddCycles (4 + 4 + 3 + 3);
    break;

  case EX_IXY_xSP:
    r_meml = Z80ReadMem (r_SP);
    r_memh = Z80ReadMem (r_SP + 1);
    Z80WriteMem (r_SP, REGL, regs);
    Z80WriteMem (r_SP + 1, REGH, regs);
    REGL = r_meml;
    REGH = r_memh;
    AddCycles (4 + 4 + 3 + 3 + 3 + 3 + 3);
    break;

  case LD_A_xIXY:
    r_A = Z80ReadMem (REG + ((offset) Z80ReadMem (r_PC)));
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_B_xIXY:
    r_B = Z80ReadMem (REG + ((offset) Z80ReadMem (r_PC)));
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_C_xIXY:
    r_C = Z80ReadMem (REG + ((offset) Z80ReadMem (r_PC)));
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_D_xIXY:
    r_D = Z80ReadMem (REG + ((offset) Z80ReadMem (r_PC)));
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_E_xIXY:
    r_E = Z80ReadMem (REG + ((offset) Z80ReadMem (r_PC)));
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case LD_xIXY_A:
    Z80WriteMem (REG + (offset) Z80ReadMem (r_PC), r_A, regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_xIXY_B:
    Z80WriteMem (REG + (offset) Z80ReadMem (r_PC), r_B, regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_xIXY_C:
    Z80WriteMem (REG + (offset) Z80ReadMem (r_PC), r_C, regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_xIXY_D:
    Z80WriteMem (REG + (offset) Z80ReadMem (r_PC), r_D, regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_xIXY_E:
    Z80WriteMem (REG + (offset) Z80ReadMem (r_PC), r_E, regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case INC_xIXY:
    r_mem = REG + (offset) Z80ReadMem (r_PC);
    r_PC++;
    tmpreg.B.l = Z80ReadMem (r_mem);
    INC (tmpreg.B.l);
    Z80WriteMem (r_mem, tmpreg.B.l, regs);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3 + 3 + 1);
    break;
  case DEC_xIXY:
    r_mem = REG + (offset) Z80ReadMem (r_PC);
    r_PC++;
    tmpreg.B.l = Z80ReadMem (r_mem);
    DEC (tmpreg.B.l);
    Z80WriteMem (r_mem, tmpreg.B.l, regs);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3 + 3 + 1);
    break;

  case ADC_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    ADC (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case SBC_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    SBC (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case ADD_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    ADD (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case SUB_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    SUB (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case AND_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    AND (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case OR_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    OR (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case XOR_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    XOR (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case CP_xIXY:
    r_meml = Z80ReadMem (REG + (offset) Z80ReadMem (r_PC));
    r_PC++;
    CP (r_meml);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case LD_IXY_NN:
    REGL = Z80ReadMem (r_PC);
    r_PC++;
    REGH = Z80ReadMem (r_PC);
    r_PC++;
    AddCycles (4 + 1 + 3 + 3 + 3);
    break;

  case LD_xIXY_N:
    r_mem = REG + (offset) Z80ReadMem (r_PC);
    r_PC++;
    Z80WriteMem (r_mem, Z80ReadMem (r_PC), regs);
    r_PC++;
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case LD_IXY_xNN:
    LOAD_rr_nn (REG);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3 + 1);
    break;

  case LD_xNN_IXY:
    STORE_nn_rr (REG);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3 + 1);
    break;


/* some undocumented opcodes: may be wrong: */
  case LD_A_IXYh:
    r_A = REGH;
    AddCycles (4 + 4);
    break;
  case LD_A_IXYl:
    r_A = REGL;
    AddCycles (4 + 4);
    break;
  case LD_B_IXYh:
    r_B = REGH;
    AddCycles (4 + 4);
    break;
  case LD_B_IXYl:
    r_B = REGL;
    AddCycles (4 + 4);
    break;
  case LD_C_IXYh:
    r_C = REGH;
    AddCycles (4 + 4);
    break;
  case LD_C_IXYl:
    r_C = REGL;
    AddCycles (4 + 4);
    break;
  case LD_D_IXYh:
    r_D = REGH;
    AddCycles (4 + 4);
    break;
  case LD_D_IXYl:
    r_D = REGL;
    AddCycles (4 + 4);
    break;
  case LD_E_IXYh:
    r_E = REGH;
    AddCycles (4 + 4);
    break;
  case LD_E_IXYl:
    r_E = REGL;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_A:
    REGH = r_A;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_B:
    REGH = r_B;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_C:
    REGH = r_C;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_D:
    REGH = r_D;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_E:
    REGH = r_E;
    AddCycles (4 + 4);
    break;
  case LD_IXYh_IXYh:
    AddCycles (4 + 4);
    break;
  case LD_IXYh_IXYl:
    REGH = REGL;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_A:
    REGL = r_A;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_B:
    REGL = r_B;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_C:
    REGL = r_C;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_D:
    REGL = r_D;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_E:
    REGL = r_E;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_IXYh:
    REGL = REGH;
    AddCycles (4 + 4);
    break;
  case LD_IXYl_IXYl:
    AddCycles (4 + 4);
    break;
  case LD_IXYh_N:
    REGH = Z80ReadMem (r_PC);
    r_PC++;
    AddCycles (4 + 4 + 3);
    break;
  case LD_IXYl_N:
    REGL = Z80ReadMem (r_PC);
    r_PC++;
    AddCycles (4 + 4 + 3);
    break;


  case ADD_IXYh:
    ADD (REGH);
    AddCycles (4 + 4);
    break;
  case ADD_IXYl:
    ADD (REGL);
    AddCycles (4 + 4);
    break;
  case ADC_IXYh:
    ADC (REGH);
    AddCycles (4 + 4);
    break;
  case ADC_IXYl:
    ADC (REGL);
    AddCycles (4 + 4);
    break;
  case SUB_IXYh:
    SUB (REGH);
    AddCycles (4 + 4);
    break;
  case SUB_IXYl:
    SUB (REGL);
    AddCycles (4 + 4);
    break;
  case SBC_IXYh:
    SBC (REGH);
    AddCycles (4 + 4);
    break;
  case SBC_IXYl:
    SBC (REGL);
    AddCycles (4 + 4);
    break;
  case AND_IXYh:
    AND (REGH);
    AddCycles (4 + 4);
    break;
  case AND_IXYl:
    AND (REGL);
    AddCycles (4 + 4);
    break;
  case XOR_IXYh:
    XOR (REGH);
    AddCycles (4 + 4);
    break;
  case XOR_IXYl:
    XOR (REGL);
    AddCycles (4 + 4);
    break;
  case OR_IXYh:
    OR (REGH);
    AddCycles (4 + 4);
    break;
  case OR_IXYl:
    OR (REGL);
    AddCycles (4 + 4);
    break;
  case CP_IXYh:
    CP (REGH);
    AddCycles (4 + 4);
    break;
  case CP_IXYl:
    CP (REGL);
    AddCycles (4 + 4);
    break;
  case INC_IXYh:
    INC (REGH);
    AddCycles (4 + 4);
    break;
  case INC_IXYl:
    INC (REGL);
    AddCycles (4 + 4);
    break;
  case DEC_IXYh:
    DEC (REGH);
    AddCycles (4 + 4);
    break;
  case DEC_IXYl:
    DEC (REGL);
    AddCycles (4 + 4);
    break;

  case LD_xIXY_H:
    r_meml = Z80ReadMem (r_PC);
    r_PC++;
    Z80WriteMem (REG + (offset) (r_meml), r_H, regs);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_xIXY_L:
    r_meml = Z80ReadMem (r_PC);
    r_PC++;
    Z80WriteMem (REG + (offset) (r_meml), r_L, regs);
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_H_xIXY:
    r_meml = Z80ReadMem (r_PC);
    r_PC++;
    r_H = Z80ReadMem (REG + (offset) (r_meml));
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;
  case LD_L_xIXY:
    r_meml = Z80ReadMem (r_PC);
    r_PC++;
    r_L = Z80ReadMem (REG + (offset) (r_meml));
    AddCycles (4 + 3 + 3 + 3 + 3 + 3);
    break;

  case PREFIX_CB:
#ifndef CPP_COMPILATION
#include "opddfdcb.c"
#else
#include "opddfdcb.cpp"
#endif
    break;

/*
case PREFIX_DD:
case PREFIX_FD:       AddCycles( 4 );
                      r_PC--;                 // decode it the next time :)
                      break;
*/

  default:
    AddCycles (4);
    r_PC--;			/* decode it the next time :) */
    SubR (1);

//    exit(1);
//    if( regs->DecodingErrors )
//    {
//      printf("z80 core: Unknown instruction: ");
//      if ( regs->we_are_on_ddfd == WE_ARE_ON_DD )
//         printf("DD ");
//      else
//         printf("FD ");
//      printf("%02Xh at PC=%04Xh.\n", Z80ReadMem(r_PC-1), r_PC-2 );
//    }
    break;
  }

#undef REG
#undef REGL
#undef REGH
