// This file is part of the Noddybox.Emulation C# suite. // // Noddybox.Emulation 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 3 of the License, or // (at your option) any later version. // // Noddybox.Emulation 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 Noddybox.Emulation. If not, see . // // Copyright (c) 2012 Ian Cowburn // using System; namespace Noddybox.Emulation.EightBit.Z80 { public partial class Z80Cpu { /// /// Decode and execute an ED-shifted opcode. /// /// The opcode. private void DecodeED(byte opcode) { ushort addr; byte b; Register16 tmp = new Register16(0); switch(opcode) { case 0x40: // IN B,(C) clock.Add(12); BC.high = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[BC.high] | H35table[BC.high]; break; case 0x41: // OUT (C),B clock.Add(12); device.Write(BC.reg, BC.high); break; case 0x42: // SBC HL,BC clock.Add(15); SBC(ref HL.reg, BC.reg); break; case 0x43: // LD (nnnn),BC clock.Add(20); addr = FetchWord(); memory.Write(addr++, BC.low); memory.Write(addr, BC.high); break; case 0x44: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x45: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x46: // IM 0 clock.Add(8); IM = 0; break; case 0x47: // LD I,A clock.Add(9); I = A; break; case 0x48: // IN C,(C) clock.Add(12); BC.low = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[BC.low] | H35table[BC.low]; break; case 0x49: // OUT (C),C clock.Add(12); device.Write(BC.reg, BC.low); break; case 0x4a: // ADC HL, BC clock.Add(15); ADC16(ref HL.reg, BC.reg); break; case 0x4b: // LD BC,(nnnn) clock.Add(20); addr = FetchWord(); BC.low = memory.Read(addr++); BC.high = memory.Read(addr); break; case 0x4c: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x4d: // RETI clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x4e: // IM 0/1 clock.Add(8); IM = 0; break; case 0x4f: // LD R,A clock.Add(9); R = A; break; case 0x50: // IN D,(C) clock.Add(12); DE.high = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[DE.high] | H35table[DE.high]; break; case 0x51: // OUT (C),D clock.Add(12); device.Write(BC.reg, DE.high); break; case 0x52: // SBC HL,DE clock.Add(15); SBC(ref HL.reg, DE.reg); break; case 0x53: // LD (nnnn),DE clock.Add(20); addr = FetchWord(); memory.Write(addr++, DE.low); memory.Write(addr, DE.high); break; case 0x54: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x55: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x56: // IM 1 clock.Add(8); IM = 1; break; case 0x57: // LD A,I clock.Add(9); A = (byte)I; F &= Z80Flags.Carry; F |= H35table[A] | SZtable[A] | (IFF2 ? Z80Flags.PV : Z80Flags.None); break; case 0x58: // IN E,(C) clock.Add(12); DE.low = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[DE.low] | H35table[DE.low]; break; case 0x59: // OUT (C),E clock.Add(12); device.Write(BC.reg, DE.low); break; case 0x5a: // ADC HL, DE clock.Add(15); ADC16(ref HL.reg, DE.reg); break; case 0x5b: // LD DE,(nnnn) clock.Add(20); addr = FetchWord(); DE.low = memory.Read(addr++); DE.high = memory.Read(addr); break; case 0x5c: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x5d: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x5e: // IM 2 clock.Add(8); IM = 2; break; case 0x5f: // LD A,R clock.Add(9); A = R; F &= Z80Flags.Carry; F |= H35table[A] | SZtable[A] | (IFF2 ? Z80Flags.PV : Z80Flags.None); break; case 0x60: // IN H,(C) clock.Add(12); HL.high = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[HL.high] | H35table[HL.high]; break; case 0x61: // OUT (C),H clock.Add(12); device.Write(BC.reg, HL.high); break; case 0x62: // SBC HL,HL clock.Add(15); SBC(ref HL.reg, HL.reg); break; case 0x63: // LD (nnnn),HL clock.Add(20); addr = FetchWord(); memory.Write(addr++, HL.low); memory.Write(addr, HL.high); break; case 0x64: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x65: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x66: // IM 0 clock.Add(8); IM = 0; break; case 0x67: // RRD clock.Add(18); b = memory.Read(HL.reg); memory.Write(HL.reg, (byte)((b >> 4)|(A << 4))); A = (byte)((A & 0xf0) | (b & 0x0f)); F &= Z80Flags.Carry; F |= PSZtable[A] | H35table[A]; break; case 0x68: // IN L,(C) clock.Add(12); HL.low = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[HL.low] | H35table[HL.low]; break; case 0x69: // OUT (C),L clock.Add(12); device.Write(BC.reg, HL.low); break; case 0x6a: // ADC HL, HL clock.Add(15); ADC16(ref HL.reg, HL.reg); break; case 0x6b: // LD HL,(nnnn) clock.Add(20); addr = FetchWord(); HL.low = memory.Read(addr++); HL.high = memory.Read(addr); break; case 0x6c: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x6d: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x6e: // IM 0/1 clock.Add(8); IM = 0; break; case 0x6f: // RLD clock.Add(18); b = memory.Read(HL.reg); memory.Write(HL.reg, (byte)((b << 4)|(A & 0x0f))); A = (byte)((A & 0xf0) | (b >> 4)); F = Z80Flags.Carry | PSZtable[A] | H35table[A]; break; case 0x70: // IN (C) clock.Add(12); b = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[b] | H35table[b]; break; case 0x71: // OUT (C) clock.Add(12); device.Write(BC.reg, 0); break; case 0x72: // SBC HL,SP clock.Add(15); SBC(ref HL.reg, SP); break; case 0x73: // LD (nnnn),SP clock.Add(20); addr = FetchWord(); memory.Write(addr++, (byte)(SP & 0xff)); memory.Write(addr, (byte)(SP >> 8)); break; case 0x74: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x75: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x76: // IM 1 clock.Add(8); IM = 1; break; case 0x77: // NOP clock.Add(18); TriggerEvent(EventType.EDHook, opcode); break; case 0x78: // IN A,(C) clock.Add(12); A = device.Read(BC.reg); F &= Z80Flags.Carry; F |= PSZtable[A] | H35table[A]; break; case 0x79: // OUT (C),A clock.Add(12); device.Write(BC.reg, A); break; case 0x7a: // ADC HL, SP clock.Add(15); ADC16(ref HL.reg, SP); break; case 0x7b: // LD SP,(nnnn) clock.Add(20); addr = FetchWord(); tmp.low = memory.Read(addr++); tmp.high = memory.Read(addr); SP = tmp.reg; break; case 0x7c: // NEG clock.Add(8); b = A; A = 0; SUB8(b); break; case 0x7d: // RETN clock.Add(14); IFF1 = IFF2; PC = POP(); break; case 0x7e: // IM 2 clock.Add(8); IM = 2; break; case 0x7f: // NOP clock.Add(8); TriggerEvent(EventType.EDHook, opcode); break; case 0xa0: // LDI clock.Add(16); LDI(); break; case 0xa1: // CPI clock.Add(16); CPI(); break; case 0xa2: // INI clock.Add(16); INI(); break; case 0xa3: // OUTI clock.Add(16); OUTI(); break; case 0xa8: // LDD clock.Add(16); LDD(); break; case 0xa9: // CPD clock.Add(16); CPD(); break; case 0xaa: // IND clock.Add(16); IND(); break; case 0xab: // OUTD clock.Add(16); OUTD(); break; case 0xb0: // LDIR clock.Add(16); LDI(); if (BC.reg > 0) { clock.Add(5); PC -= 2; } break; case 0xb1: // CPIR clock.Add(16); CPI(); if (BC.reg > 0 && (F & Z80Flags.Zero) == Z80Flags.None) { clock.Add(5); PC -= 2; } break; case 0xb2: // INIR clock.Add(16); INI(); if (BC.high > 0) { clock.Add(5); PC -= 2; } break; case 0xb3: // OTIR clock.Add(16); OUTI(); if (BC.high > 0) { clock.Add(5); PC -= 2; } break; case 0xb8: // LDDR clock.Add(16); LDD(); if (BC.reg > 0) { clock.Add(5); PC -= 2; } break; case 0xb9: // CPDR clock.Add(16); CPD(); if (BC.reg > 0 && (F & Z80Flags.Zero) == Z80Flags.None) { clock.Add(5); PC -= 2; } break; case 0xba: // INDR clock.Add(16); IND(); if (BC.high > 0) { clock.Add(5); PC -= 2; } break; case 0xbb: // OTDR clock.Add(16); OUTD(); if (BC.high > 0) { clock.Add(5); PC -= 2; } break; default: // NOP clock.Add(8); TriggerEvent(EventType.EDHook, opcode); break; } } } }