// 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;
}
}
}
}