MCUME/MCUME_teensy/teensyspeccy/altz80/op_ed.h

603 wiersze
14 KiB
C
Executable File

/*====================================================================
opcodes_ed.c -> This file executes the ED opcodes.
Another prefix that "creates" new instructions. This prefix also
introduces some undocumented opcodes that we've tried to include
here. Maybe their implementation it's wrong: if you can find any
mistake about how we have implemented/interpreted them, please
let us know.
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 = ED opcode = 4 + 4 */
opcode = Z80ReadMem (r_PC);
r_PC++;
switch (opcode)
{
case LD_BC_xNNe:
LOAD_rr_nn (r_BC);
AddCycles (4 + 4 + 12);
break;
case LD_DE_xNNe:
LOAD_rr_nn (r_DE);
AddCycles (4 + 4 + 12);
break;
case LD_HL_xNNe:
LOAD_rr_nn (r_HL);
AddCycles (4 + 4 + 12);
break;
case LD_SP_xNNe:
LOAD_rr_nn (r_SP);
AddCycles (4 + 4 + 12);
break;
case LD_xNNe_BC:
STORE_nn_rr (r_BC);
AddCycles (4 + 4 + 12);
break;
case LD_xNNe_DE:
STORE_nn_rr (r_DE);
AddCycles (4 + 4 + 12);
break;
case LD_xNNe_HL:
STORE_nn_rr (r_HL);
AddCycles (4 + 4 + 12);
break;
case LD_xNNe_SP:
STORE_nn_rr (r_SP);
AddCycles (4 + 4 + 12);
break;
case NEG:
case ED_5C:
case ED_74:
case ED_7C:
case ED_6C:
case ED_54:
case ED_4C:
case ED_64:
NEG_A ();
AddCycles (4 + 4);
break;
case RETI:
case RETN:
case ED_65:
case ED_6D:
case ED_75:
case ED_7D:
case ED_5D:
case ED_55:
r_IFF1 = r_IFF2;
RET_nn ();
AddCycles (4 + 4 + 6);
break;
case IM_0:
case ED_4E: /* * IM 0/1 */
case ED_6E:
case ED_66:
regs->IM = 0;
AddCycles (4 + 4);
break; /* * IM 0 */
case IM_1:
case ED_76:
regs->IM = 1;
AddCycles (4 + 4);
break;
case IM_2:
case ED_7E:
regs->IM = 2;
AddCycles (4 + 4);
break;
case ED_77:
case ED_7F:
AddCycles (4 + 4);
break; /* * NOP */
case OUT_xC_B:
Z80OutPort (regs, r_BC, r_B);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_C:
Z80OutPort (regs, r_BC, r_C);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_D:
Z80OutPort (regs, r_BC, r_D);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_E:
Z80OutPort (regs, r_BC, r_E);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_H:
Z80OutPort (regs, r_BC, r_H);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_L:
Z80OutPort (regs, r_BC, r_L);
AddCycles (4 + 4 + 4);
break;
case OUT_xC_A:
Z80OutPort (regs, r_BC, r_A);
AddCycles (4 + 4 + 4);
break;
/* * OUT (C), 0 */
case ED_71:
Z80OutPort (regs, r_BC, 0);
AddCycles (4 + 4 + 4);
break;
case IN_B_xC:
IN_PORT (r_B, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_C_xC:
IN_PORT (r_C, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_D_xC:
IN_PORT (r_D, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_E_xC:
IN_PORT (r_E, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_L_xC:
IN_PORT (r_L, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_H_xC:
IN_PORT (r_H, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_A_xC:
IN_PORT (r_A, r_BC);
AddCycles (4 + 4 + 4);
break;
case IN_F_xC:
IN_PORT (r_meml, r_BC);
AddCycles (4 + 4 + 4);
break;
case LD_A_I:
r_A = regs->I;
r_F = (r_F & FLAG_C) | sz53_table[r_A] | (regs->IFF2 ? FLAG_V : 0);
AddCycles (4 + 4 + 1);
break;
case LD_I_A:
regs->I = r_A;
AddCycles (4 + 4 + 1);
break;
case LD_A_R:
r_A = (regs->R.W & 0x7f) | (regs->R.W & 0x80);
r_F = (r_F & FLAG_C) | sz53_table[r_A] | (regs->IFF2 ? FLAG_V : 0);
AddCycles (4 + 4 + 1);
break;
case LD_R_A:
regs->R.W = r_A;
AddCycles (4 + 4 + 1);
break;
case ADC_HL_BC:
ADC_WORD (r_BC);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case ADC_HL_DE:
ADC_WORD (r_DE);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case ADC_HL_HL:
ADC_WORD (r_HL);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case ADC_HL_SP:
ADC_WORD (r_SP);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case SBC_HL_BC:
SBC_WORD (r_BC);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case SBC_HL_DE:
SBC_WORD (r_DE);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case SBC_HL_HL:
SBC_WORD (r_HL);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case SBC_HL_SP:
SBC_WORD (r_SP);
AddCycles (4 + 4 + 4 + 1 + 2);
break;
case RRD:
r_meml = Z80ReadMem (r_HL);
Z80WriteMem (r_HL, (r_A << 4) | (r_meml >> 4), regs);
r_A = (r_A & 0xf0) | (r_meml & 0x0f);
r_F = (r_F & FLAG_C) | sz53p_table[r_A];
AddCycles (4 + 4 + 10);
break;
case RLD:
r_meml = Z80ReadMem (r_HL);
Z80WriteMem (r_HL, (r_meml << 4) | (r_A & 0x0f), regs);
r_A = (r_A & 0xf0) | (r_meml >> 4);
r_F = (r_F & FLAG_C) | sz53p_table[r_A];
AddCycles (4 + 4 + 10);
break;
case LDI:
r_meml = Z80ReadMem (r_HL);
r_HL++;
Z80WriteMem (r_DE, r_meml, regs);
r_DE++;
r_BC--;
r_meml += r_A;
r_F = (r_F & (FLAG_C | FLAG_Z | FLAG_S)) |
(r_BC ? FLAG_V : 0) | (r_meml & FLAG_3) |
((r_meml & 0x02) ? FLAG_5 : 0);
AddCycles (4 + 4 + 4 + 4);
break;
case LDIR:
r_meml = Z80ReadMem (r_HL);
r_HL++;
Z80WriteMem (r_DE, r_meml, regs);
r_DE++;
r_BC--;
r_meml += r_A;
r_F = (r_F & (FLAG_C | FLAG_Z | FLAG_S))
| (r_meml & FLAG_3) | ((r_meml & 0x02) ? FLAG_5 : 0) ;
// | (r_BC ? FLAG_V : 0) ;
AddCycles (4 + 4 + 4 + 4);
if (r_BC)
{
r_PC -= 2;
AddCycles (5);
}
break;
case LDD:
r_meml = Z80ReadMem (r_HL);
r_HL--;
Z80WriteMem (r_DE, r_meml, regs);
r_DE--;
r_BC--;
r_meml += r_A;
r_F = (r_F & (FLAG_C | FLAG_Z | FLAG_S)) |
(r_BC ? FLAG_V : 0) | (r_meml & FLAG_3) |
((r_meml & 0x02) ? FLAG_5 : 0);
AddCycles (4 + 4 + 4 + 4);
break;
case LDDR:
r_meml = Z80ReadMem (r_HL);
Z80WriteMem (r_DE, r_meml, regs);
r_HL--;
r_DE--;
r_BC--;
r_meml += r_A;
r_F = (r_F & (FLAG_C | FLAG_Z | FLAG_S))
| (r_meml & FLAG_3) | ((r_meml & 0x02) ? FLAG_5 : 0) ;
// | (r_BC ? FLAG_V : 0) ;
AddCycles (4 + 4 + 4 + 4 + 1);
if (r_BC)
{
r_PC -= 2;
AddCycles (4);
}
break;
// I had lots of problems with CPI, INI, CPD, IND, OUTI, OUTD and so...
// Thanks a lot to Philip Kendall for letting me to take a look to his
// fuse emulator and allowing me to use their flag routines :-)
case CPI:
r_meml = Z80ReadMem (r_HL);
r_memh = r_A - r_meml;
r_opl = ((r_A & 0x08) >> 3) |
(((r_meml) & 0x08) >> 2) | ((r_meml & 0x08) >> 1);
r_HL++;
r_BC--;
r_F = (r_F & FLAG_C) |
(r_BC ? (FLAG_V | FLAG_N) : FLAG_N) |
halfcarry_sub_table[r_opl] | (r_memh ? 0 : FLAG_Z) | (r_memh & FLAG_S);
if (r_F & FLAG_H)
r_memh--;
r_F |= (r_memh & FLAG_3) | ((r_memh & 0x02) ? FLAG_5 : 0);
AddCycles (4 + 4 + 4 + 4);
break;
case CPIR:
r_meml = Z80ReadMem (r_HL);
r_memh = r_A - r_meml;
r_opl = ((r_A & 0x08) >> 3) |
(((r_meml) & 0x08) >> 2) | ((r_meml & 0x08) >> 1);
r_HL++;
r_BC--;
r_F = (r_F & FLAG_C) |
(r_BC ? (FLAG_V | FLAG_N) : FLAG_N) |
halfcarry_sub_table[r_opl] | (r_memh ? 0 : FLAG_Z) | (r_memh & FLAG_S);
if (r_F & FLAG_H)
r_memh--;
r_F |= (r_memh & FLAG_3) | ((r_memh & 0x02) ? FLAG_5 : 0);
if ((r_F & (FLAG_V | FLAG_Z)) == FLAG_V)
{
AddCycles (5);
r_PC -= 2;
}
AddCycles (4 + 4 + 4 + 4);
break;
case CPD:
r_meml = Z80ReadMem (r_HL);
r_memh = r_A - r_meml;
r_opl = ((r_A & 0x08) >> 3) |
(((r_meml) & 0x08) >> 2) | ((r_memh & 0x08) >> 1);
r_HL--;
r_BC--;
r_F = (r_F & FLAG_C) |
(r_BC ? (FLAG_V | FLAG_N) : FLAG_N) |
halfcarry_sub_table[r_opl] | (r_memh ? 0 : FLAG_Z) | (r_memh & FLAG_S);
if (r_F & FLAG_H)
r_memh--;
r_F |= (r_memh & FLAG_3) | ((r_memh & 0x02) ? FLAG_5 : 0);
AddCycles (4 + 4 + 4 + 4);
break;
case CPDR:
r_meml = Z80ReadMem (r_HL);
r_memh = r_A - r_meml;
r_opl = ((r_A & 0x08) >> 3) |
(((r_meml) & 0x08) >> 2) | ((r_memh & 0x08) >> 1);
r_HL--;
r_BC--;
r_F = (r_F & FLAG_C) |
(r_BC ? (FLAG_V | FLAG_N) : FLAG_N) |
halfcarry_sub_table[r_opl] | (r_memh ? 0 : FLAG_Z) | (r_memh & FLAG_S);
if (r_F & FLAG_H)
r_memh--;
r_F |= (r_memh & FLAG_3) | ((r_memh & 0x02) ? FLAG_5 : 0);
if ((r_F & (FLAG_V | FLAG_Z)) == FLAG_V)
{
AddCycles (5);
r_PC -= 2;
}
AddCycles (4 + 4 + 4 + 4);
break;
// I/O block instructions by Metalbrain - 14-5-2001
case IND:
r_meml = Z80InPort (regs, (r_BC));
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80WriteMem (r_HL, r_meml, regs);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl--;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_dec1_table[(r_opl)]);
r_HL--;
AddCycles (4 + 4 + 4 + 4);
break;
case INDR:
r_meml = Z80InPort (regs, (r_BC));
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80WriteMem (r_HL, r_meml, regs);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl--;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_dec1_table[(r_opl)]);
r_HL--;
if (r_B)
{
r_PC -= 2;
AddCycles (5);
}
AddCycles (4 + 4 + 4 + 4);
break;
case INI:
r_meml = Z80InPort (regs, (r_BC));
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80WriteMem (r_HL, r_meml, regs);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl++;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_inc1_table[(r_opl)]);
r_HL++;
AddCycles (4 + 4 + 4 + 4);
break;
case INIR:
r_meml = Z80InPort (regs, (r_BC));
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80WriteMem (r_HL, r_meml, regs);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl++;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_inc1_table[(r_opl)]);
r_HL++;
if (r_B)
{
r_PC -= 2;
AddCycles (5);
}
AddCycles (4 + 4 + 4 + 4);
break;
case OUTI:
r_meml = Z80ReadMem (r_HL);
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80OutPort (regs, r_BC, r_meml);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl++;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_inc1_table[(r_opl)]);
r_HL++;
AddCycles (4 + 4 + 4 + 4);
break;
case OTIR:
r_meml = Z80ReadMem (r_HL);
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80OutPort (regs, r_BC, r_meml);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl++;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_inc1_table[(r_opl)]);
r_HL++;
if (r_B)
{
r_PC -= 2;
AddCycles (5);
}
AddCycles (4 + 4 + 4 + 4);
break;
case OUTD:
r_meml = Z80ReadMem (r_HL);
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80OutPort (regs, r_BC, r_meml);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl--;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_dec1_table[(r_opl)]);
r_HL--;
AddCycles (4 + 4 + 4 + 4);
break;
case OTDR:
r_meml = Z80ReadMem (r_HL);
r_memh = 0;
r_F = (r_F & FLAG_C) | ((r_B) & 0x0f ? 0 : FLAG_H) | FLAG_N;
(r_B)--;
r_F |= ((r_B) == 0x7f ? FLAG_V : 0) | sz53_table[(r_B)];
r_F &= 0xE8;
Z80OutPort (regs, r_BC, r_meml);
r_F |= ((r_meml & 0x80) >> 6);
r_opl = r_C;
r_oph = 0;
r_opl--;
r_op += r_mem;
r_oph += (r_oph << 4);
r_F |= r_oph;
r_opl = (r_meml & 7) + ((r_C & 7) << 3);
r_F |= (ioblock_2_table[(r_B)] ^ ioblock_dec1_table[(r_opl)]);
r_HL--;
if (r_B)
{
r_PC -= 2;
AddCycles (5);
}
AddCycles (4 + 4 + 4 + 4);
break;
// End of Metalbrain's contribution
case PREFIX_ED:
AddCycles (4); /* ED ED xx = 12 cycles min = 4+8 */
r_PC--;
break;
default:
// exit(1);
AddCycles (4 + 4); /* Just a NOP */
break;
}