/*====================================================================/* 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(r_B, r_BC); AddCycles( 4+4+4 ); break; case IN_C_xC : IN(r_C, r_BC); AddCycles( 4+4+4 ); break; case IN_D_xC : IN(r_D, r_BC); AddCycles( 4+4+4 ); break; case IN_E_xC : IN(r_E, r_BC); AddCycles( 4+4+4 ); break; case IN_L_xC : IN(r_L, r_BC); AddCycles( 4+4+4 ); break; case IN_H_xC : IN(r_H, r_BC); AddCycles( 4+4+4 ); break; case IN_A_xC : IN(r_A, r_BC); AddCycles( 4+4+4 ); break; case IN_F_xC : IN(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_BC ? FLAG_V:0 ) | ( r_meml & FLAG_3 ) | ((r_meml & 0x02) ? FLAG_5 : 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_BC ? FLAG_V : 0 ) | ( r_meml & FLAG_3 ) | ((r_meml & 0x02) ? FLAG_5 : 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; /* // OUTI contributed by Alvaro Alea case OUTI : Z80OutPort( regs, r_BC, Z80ReadMem( r_HL )) ; r_HL++ ; r_B-- ; if (r_B==0) r_F |= FLAG_Z; else r_F &= !FLAG_Z; r_F |= FLAG_N; AddCycles( 4+4+4+4 ); break; */ // I/O block instructions by Metalbrain - 14-5-2001 case IND : r_meml = Z80InPort((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((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((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((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 */ ///!!! if(regs->DecodingErrors) ///!!! printf( "z80 core: Unknown instruction: ED %02Xh at PC=%04Xh.\n", ///!!! Z80ReadMem(r_PC-1),r_PC-2 ); break; }