1298 lines
42 KiB
C#
1298 lines
42 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace MCEmuCore.GBMonolith
|
|
{
|
|
public struct OpCode
|
|
{
|
|
public readonly byte Instruction;
|
|
public byte? Arg1;
|
|
public byte? Arg2;
|
|
}
|
|
class Cpu
|
|
{
|
|
private readonly CpuRegisters registers;
|
|
#region OpCodes
|
|
|
|
private readonly List<Func<OpCode, int>> OpCodeArray;
|
|
#endregion
|
|
|
|
public Cpu()
|
|
{
|
|
registers = new CpuRegisters();
|
|
|
|
OpCodeArray = new List<Func<OpCode, int>>()
|
|
{
|
|
#region OpCodes
|
|
#region OpCodes 0x00-0x0F
|
|
// 0x00
|
|
(op) => {
|
|
// NOP
|
|
registers.PC += 1;
|
|
return 4;
|
|
},
|
|
// 0x01
|
|
(op) => {
|
|
// LD BC,d16
|
|
if (op.Arg1.HasValue && op.Arg2.HasValue)
|
|
{
|
|
registers.BC = (ushort)(op.Arg2 + (op.Arg1 << 8));
|
|
registers.PC += 3;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing arguments for LD BC");
|
|
}
|
|
},
|
|
// 0x02
|
|
(op) => {
|
|
// LD (BC), A
|
|
throw new NotImplementedException("LD (BC), A");
|
|
},
|
|
// 0x03
|
|
(op) => {
|
|
registers.BC += 1;
|
|
registers.PC += 1;
|
|
return 8;
|
|
},
|
|
// 0x04
|
|
(op) => {
|
|
// INC B
|
|
registers.B = IncrementRegister(registers.B);
|
|
|
|
return 4;
|
|
},
|
|
// 0x05
|
|
(op) => {
|
|
// DEC B
|
|
registers.B = DecrementRegister(registers.B);
|
|
|
|
return 4;
|
|
},
|
|
// 0x06
|
|
(op) => {
|
|
// LD B,d8
|
|
if (op.Arg1.HasValue)
|
|
{
|
|
registers.B = op.Arg1.Value;
|
|
registers.PC += 2;
|
|
return 8;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing arguments for LD B");
|
|
}
|
|
},
|
|
// 0x07
|
|
(op) => {
|
|
// RLCA
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b1000_0000) != 0;
|
|
|
|
registers.A = (byte)((registers.A << 1) + (registers.A >> 7));
|
|
registers.PC += 1;
|
|
return 4;
|
|
},
|
|
// 0x08
|
|
(op) => {
|
|
// LD (a16), SP
|
|
// Load SP into address
|
|
throw new NotImplementedException("LD (a16), SP");
|
|
},
|
|
// 0x09
|
|
(op) => {
|
|
// ADD HL, BC
|
|
registers.HL = AddWideRegisters(registers.HL, registers.BC);
|
|
|
|
return 8;
|
|
},
|
|
// 0x0A
|
|
(op) => {
|
|
// LD A, (BC)
|
|
// Load byte at address stored in BC into A
|
|
throw new NotImplementedException("LD A, (BC)");
|
|
},
|
|
// 0x0B
|
|
(op) => {
|
|
// DEC BC
|
|
registers.BC -= 1;
|
|
registers.PC += 1;
|
|
return 8;
|
|
},
|
|
// 0x0C
|
|
(op) => {
|
|
// INC C
|
|
registers.C = IncrementRegister(registers.C);
|
|
|
|
return 4;
|
|
},
|
|
// 0x0D
|
|
(op) => {
|
|
// DEC C
|
|
registers.C = DecrementRegister(registers.C);
|
|
|
|
return 4;
|
|
},
|
|
// 0x0E
|
|
(op) => {
|
|
// LD C,d8
|
|
if (op.Arg1.HasValue)
|
|
{
|
|
registers.C = op.Arg1.Value;
|
|
registers.PC += 2;
|
|
return 8;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing argument for LD B");
|
|
}
|
|
},
|
|
// 0x0F
|
|
(op) => {
|
|
// RRCA
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b0000_0001) != 0;
|
|
|
|
registers.A = (byte)((registers.A >> 1) + (registers.A << 7));
|
|
registers.PC += 1;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x10-0x1F
|
|
// 0x10
|
|
(op) => {
|
|
// STOP 0
|
|
// Halts CPU & LCD until button pressed
|
|
throw new NotImplementedException("STOP");
|
|
},
|
|
// 0x11
|
|
(op) => {
|
|
// LD DE, d16
|
|
if (op.Arg1.HasValue && op.Arg2.HasValue)
|
|
{
|
|
registers.DE = (ushort)(op.Arg2 + (op.Arg1 << 8));
|
|
registers.PC += 3;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing arguments for LD DE");
|
|
}
|
|
},
|
|
// 0x12
|
|
(op) => {
|
|
// LD (DE), A
|
|
throw new NotImplementedException("0x12");
|
|
},
|
|
// 0x13
|
|
(op) => {
|
|
// INC DE
|
|
registers.DE += 1;
|
|
registers.PC += 1;
|
|
return 8;
|
|
},
|
|
// 0x14
|
|
(op) => {
|
|
registers.D = IncrementRegister(registers.D);
|
|
|
|
return 4;
|
|
},
|
|
// 0x15
|
|
(op) => {
|
|
registers.D = DecrementRegister(registers.D);
|
|
|
|
return 4;
|
|
},
|
|
// 0x16
|
|
(op) => {
|
|
if (op.Arg1.HasValue)
|
|
{
|
|
registers.D = op.Arg1.Value;
|
|
registers.PC += 2;
|
|
return 8;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing arguments for LD D");
|
|
}
|
|
},
|
|
// 0x17
|
|
(op) => {
|
|
// RLA
|
|
int carryBit = registers.Flags.Carry ? 1 : 0;
|
|
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b1000_0000) != 0;
|
|
|
|
registers.A = (byte)((registers.A << 1) + carryBit);
|
|
registers.PC += 1;
|
|
return 4;
|
|
},
|
|
// 0x18
|
|
(op) => {
|
|
if (op.Arg1.HasValue)
|
|
{
|
|
byte relativeJump = op.Arg1.Value;
|
|
registers.PC += (ushort)(1 + relativeJump);
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing argument for JR r");
|
|
}
|
|
},
|
|
// 0x19
|
|
(op) => {
|
|
// ADD HL, DE
|
|
registers.HL = AddWideRegisters(registers.HL, registers.DE);
|
|
|
|
return 8;
|
|
},
|
|
// 0x1A
|
|
(op) => {
|
|
// LD A, (DE)
|
|
// Load byte at address stored in DE into A
|
|
throw new NotImplementedException("LD A, (DE)");
|
|
},
|
|
// 0x1B
|
|
(op) => {
|
|
// DEC DE
|
|
registers.DE -= 1;
|
|
registers.PC += 1;
|
|
|
|
return 8;
|
|
},
|
|
// 0x1C
|
|
(op) => {
|
|
registers.E = IncrementRegister(registers.E);
|
|
|
|
return 4;
|
|
},
|
|
// 0x1D
|
|
(op) => {
|
|
registers.E = IncrementRegister(registers.E);
|
|
|
|
return 4;
|
|
},
|
|
// 0x1E
|
|
(op) => {
|
|
if (op.Arg1.HasValue)
|
|
{
|
|
registers.E = op.Arg1.Value;
|
|
registers.PC += 2;
|
|
return 8;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalInstructionException(op, "Missing arguments for LD E");
|
|
}
|
|
},
|
|
// 0x1F
|
|
(op) => {
|
|
// RRA
|
|
int carryBit = registers.Flags.Carry ? 1 : 0;
|
|
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b0000_0001) != 0;
|
|
|
|
registers.A = (byte)((registers.A >> 1) + (carryBit << 7));
|
|
registers.PC += 1;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x20-0x2F
|
|
// 0x20
|
|
(op) => {
|
|
throw new NotImplementedException("0x20");
|
|
},
|
|
// 0x21
|
|
(op) => {
|
|
throw new NotImplementedException("0x21");
|
|
},
|
|
// 0x22
|
|
(op) => {
|
|
throw new NotImplementedException("0x22");
|
|
},
|
|
// 0x23
|
|
(op) => {
|
|
throw new NotImplementedException("0x23");
|
|
},
|
|
// 0x24
|
|
(op) => {
|
|
throw new NotImplementedException("0x24");
|
|
},
|
|
// 0x25
|
|
(op) => {
|
|
throw new NotImplementedException("0x25");
|
|
},
|
|
// 0x26
|
|
(op) => {
|
|
throw new NotImplementedException("0x26");
|
|
},
|
|
// 0x27
|
|
(op) => {
|
|
throw new NotImplementedException("0x27");
|
|
},
|
|
// 0x28
|
|
(op) => {
|
|
throw new NotImplementedException("0x28");
|
|
},
|
|
// 0x29
|
|
(op) => {
|
|
throw new NotImplementedException("0x29");
|
|
},
|
|
// 0x2A
|
|
(op) => {
|
|
throw new NotImplementedException("0x2A");
|
|
},
|
|
// 0x2B
|
|
(op) => {
|
|
throw new NotImplementedException("0x2B");
|
|
},
|
|
// 0x2C
|
|
(op) => {
|
|
throw new NotImplementedException("0x2C");
|
|
},
|
|
// 0x2D
|
|
(op) => {
|
|
throw new NotImplementedException("0x2D");
|
|
},
|
|
// 0x2E
|
|
(op) => {
|
|
throw new NotImplementedException("0x2E");
|
|
},
|
|
// 0x2F
|
|
(op) => {
|
|
throw new NotImplementedException("0x2F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x30-0x3F
|
|
// 0x30
|
|
(op) => {
|
|
throw new NotImplementedException("0x30");
|
|
},
|
|
// 0x31
|
|
(op) => {
|
|
throw new NotImplementedException("0x31");
|
|
},
|
|
// 0x32
|
|
(op) => {
|
|
throw new NotImplementedException("0x32");
|
|
},
|
|
// 0x33
|
|
(op) => {
|
|
throw new NotImplementedException("0x33");
|
|
},
|
|
// 0x34
|
|
(op) => {
|
|
throw new NotImplementedException("0x34");
|
|
},
|
|
// 0x35
|
|
(op) => {
|
|
throw new NotImplementedException("0x35");
|
|
},
|
|
// 0x36
|
|
(op) => {
|
|
throw new NotImplementedException("0x36");
|
|
},
|
|
// 0x37
|
|
(op) => {
|
|
throw new NotImplementedException("0x37");
|
|
},
|
|
// 0x38
|
|
(op) => {
|
|
throw new NotImplementedException("0x38");
|
|
},
|
|
// 0x39
|
|
(op) => {
|
|
throw new NotImplementedException("0x39");
|
|
},
|
|
// 0x3A
|
|
(op) => {
|
|
throw new NotImplementedException("0x3A");
|
|
},
|
|
// 0x3B
|
|
(op) => {
|
|
throw new NotImplementedException("0x3B");
|
|
},
|
|
// 0x3C
|
|
(op) => {
|
|
throw new NotImplementedException("0x3C");
|
|
},
|
|
// 0x3D
|
|
(op) => {
|
|
throw new NotImplementedException("0x3D");
|
|
},
|
|
// 0x3E
|
|
(op) => {
|
|
throw new NotImplementedException("0x3E");
|
|
},
|
|
// 0x3F
|
|
(op) => {
|
|
throw new NotImplementedException("0x3F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x40-0x4F
|
|
// 0x40
|
|
(op) => {
|
|
throw new NotImplementedException("0x40");
|
|
},
|
|
// 0x41
|
|
(op) => {
|
|
throw new NotImplementedException("0x41");
|
|
},
|
|
// 0x42
|
|
(op) => {
|
|
throw new NotImplementedException("0x42");
|
|
},
|
|
// 0x43
|
|
(op) => {
|
|
throw new NotImplementedException("0x43");
|
|
},
|
|
// 0x44
|
|
(op) => {
|
|
throw new NotImplementedException("0x44");
|
|
},
|
|
// 0x45
|
|
(op) => {
|
|
throw new NotImplementedException("0x45");
|
|
},
|
|
// 0x46
|
|
(op) => {
|
|
throw new NotImplementedException("0x46");
|
|
},
|
|
// 0x47
|
|
(op) => {
|
|
throw new NotImplementedException("0x47");
|
|
},
|
|
// 0x48
|
|
(op) => {
|
|
throw new NotImplementedException("0x48");
|
|
},
|
|
// 0x49
|
|
(op) => {
|
|
throw new NotImplementedException("0x49");
|
|
},
|
|
// 0x4A
|
|
(op) => {
|
|
throw new NotImplementedException("0x4A");
|
|
},
|
|
// 0x4B
|
|
(op) => {
|
|
throw new NotImplementedException("0x4B");
|
|
},
|
|
// 0x4C
|
|
(op) => {
|
|
throw new NotImplementedException("0x4C");
|
|
},
|
|
// 0x4D
|
|
(op) => {
|
|
throw new NotImplementedException("0x4D");
|
|
},
|
|
// 0x4E
|
|
(op) => {
|
|
throw new NotImplementedException("0x4E");
|
|
},
|
|
// 0x4F
|
|
(op) => {
|
|
throw new NotImplementedException("0x4F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x50-0x5F
|
|
// 0x50
|
|
(op) => {
|
|
throw new NotImplementedException("0x50");
|
|
},
|
|
// 0x51
|
|
(op) => {
|
|
throw new NotImplementedException("0x51");
|
|
},
|
|
// 0x52
|
|
(op) => {
|
|
throw new NotImplementedException("0x52");
|
|
},
|
|
// 0x53
|
|
(op) => {
|
|
throw new NotImplementedException("0x53");
|
|
},
|
|
// 0x54
|
|
(op) => {
|
|
throw new NotImplementedException("0x54");
|
|
},
|
|
// 0x55
|
|
(op) => {
|
|
throw new NotImplementedException("0x55");
|
|
},
|
|
// 0x56
|
|
(op) => {
|
|
throw new NotImplementedException("0x56");
|
|
},
|
|
// 0x57
|
|
(op) => {
|
|
throw new NotImplementedException("0x57");
|
|
},
|
|
// 0x58
|
|
(op) => {
|
|
throw new NotImplementedException("0x58");
|
|
},
|
|
// 0x59
|
|
(op) => {
|
|
throw new NotImplementedException("0x59");
|
|
},
|
|
// 0x5A
|
|
(op) => {
|
|
throw new NotImplementedException("0x5A");
|
|
},
|
|
// 0x5B
|
|
(op) => {
|
|
throw new NotImplementedException("0x5B");
|
|
},
|
|
// 0x5C
|
|
(op) => {
|
|
throw new NotImplementedException("0x5C");
|
|
},
|
|
// 0x5D
|
|
(op) => {
|
|
throw new NotImplementedException("0x5D");
|
|
},
|
|
// 0x5E
|
|
(op) => {
|
|
throw new NotImplementedException("0x5E");
|
|
},
|
|
// 0x5F
|
|
(op) => {
|
|
throw new NotImplementedException("0x5F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x60-0x6F
|
|
// 0x60
|
|
(op) => {
|
|
throw new NotImplementedException("0x60");
|
|
},
|
|
// 0x61
|
|
(op) => {
|
|
throw new NotImplementedException("0x61");
|
|
},
|
|
// 0x62
|
|
(op) => {
|
|
throw new NotImplementedException("0x62");
|
|
},
|
|
// 0x63
|
|
(op) => {
|
|
throw new NotImplementedException("0x63");
|
|
},
|
|
// 0x64
|
|
(op) => {
|
|
throw new NotImplementedException("0x64");
|
|
},
|
|
// 0x65
|
|
(op) => {
|
|
throw new NotImplementedException("0x65");
|
|
},
|
|
// 0x66
|
|
(op) => {
|
|
throw new NotImplementedException("0x66");
|
|
},
|
|
// 0x67
|
|
(op) => {
|
|
throw new NotImplementedException("0x67");
|
|
},
|
|
// 0x68
|
|
(op) => {
|
|
throw new NotImplementedException("0x68");
|
|
},
|
|
// 0x69
|
|
(op) => {
|
|
throw new NotImplementedException("0x69");
|
|
},
|
|
// 0x6A
|
|
(op) => {
|
|
throw new NotImplementedException("0x6A");
|
|
},
|
|
// 0x6B
|
|
(op) => {
|
|
throw new NotImplementedException("0x6B");
|
|
},
|
|
// 0x6C
|
|
(op) => {
|
|
throw new NotImplementedException("0x6C");
|
|
},
|
|
// 0x6D
|
|
(op) => {
|
|
throw new NotImplementedException("0x6D");
|
|
},
|
|
// 0x6E
|
|
(op) => {
|
|
throw new NotImplementedException("0x6E");
|
|
},
|
|
// 0x6F
|
|
(op) => {
|
|
throw new NotImplementedException("0x6F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x70-0x7F
|
|
// 0x70
|
|
(op) => {
|
|
throw new NotImplementedException("0x70");
|
|
},
|
|
// 0x71
|
|
(op) => {
|
|
throw new NotImplementedException("0x71");
|
|
},
|
|
// 0x72
|
|
(op) => {
|
|
throw new NotImplementedException("0x72");
|
|
},
|
|
// 0x73
|
|
(op) => {
|
|
throw new NotImplementedException("0x73");
|
|
},
|
|
// 0x74
|
|
(op) => {
|
|
throw new NotImplementedException("0x74");
|
|
},
|
|
// 0x75
|
|
(op) => {
|
|
throw new NotImplementedException("0x75");
|
|
},
|
|
// 0x76
|
|
(op) => {
|
|
throw new NotImplementedException("0x76");
|
|
},
|
|
// 0x77
|
|
(op) => {
|
|
throw new NotImplementedException("0x77");
|
|
},
|
|
// 0x78
|
|
(op) => {
|
|
throw new NotImplementedException("0x78");
|
|
},
|
|
// 0x79
|
|
(op) => {
|
|
throw new NotImplementedException("0x79");
|
|
},
|
|
// 0x7A
|
|
(op) => {
|
|
throw new NotImplementedException("0x7A");
|
|
},
|
|
// 0x7B
|
|
(op) => {
|
|
throw new NotImplementedException("0x7B");
|
|
},
|
|
// 0x7C
|
|
(op) => {
|
|
throw new NotImplementedException("0x7C");
|
|
},
|
|
// 0x7D
|
|
(op) => {
|
|
throw new NotImplementedException("0x7D");
|
|
},
|
|
// 0x7E
|
|
(op) => {
|
|
throw new NotImplementedException("0x7E");
|
|
},
|
|
// 0x7F
|
|
(op) => {
|
|
throw new NotImplementedException("0x7F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x80-0x8F
|
|
// 0x80
|
|
(op) => {
|
|
throw new NotImplementedException("0x80");
|
|
},
|
|
// 0x81
|
|
(op) => {
|
|
throw new NotImplementedException("0x81");
|
|
},
|
|
// 0x82
|
|
(op) => {
|
|
throw new NotImplementedException("0x82");
|
|
},
|
|
// 0x83
|
|
(op) => {
|
|
throw new NotImplementedException("0x83");
|
|
},
|
|
// 0x84
|
|
(op) => {
|
|
throw new NotImplementedException("0x84");
|
|
},
|
|
// 0x85
|
|
(op) => {
|
|
throw new NotImplementedException("0x85");
|
|
},
|
|
// 0x86
|
|
(op) => {
|
|
throw new NotImplementedException("0x86");
|
|
},
|
|
// 0x87
|
|
(op) => {
|
|
throw new NotImplementedException("0x87");
|
|
},
|
|
// 0x88
|
|
(op) => {
|
|
throw new NotImplementedException("0x88");
|
|
},
|
|
// 0x89
|
|
(op) => {
|
|
throw new NotImplementedException("0x89");
|
|
},
|
|
// 0x8A
|
|
(op) => {
|
|
throw new NotImplementedException("0x8A");
|
|
},
|
|
// 0x8B
|
|
(op) => {
|
|
throw new NotImplementedException("0x8B");
|
|
},
|
|
// 0x8C
|
|
(op) => {
|
|
throw new NotImplementedException("0x8C");
|
|
},
|
|
// 0x8D
|
|
(op) => {
|
|
throw new NotImplementedException("0x8D");
|
|
},
|
|
// 0x8E
|
|
(op) => {
|
|
throw new NotImplementedException("0x8E");
|
|
},
|
|
// 0x8F
|
|
(op) => {
|
|
throw new NotImplementedException("0x8F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x90-0x9F
|
|
// 0x90
|
|
(op) => {
|
|
throw new NotImplementedException("0x90");
|
|
},
|
|
// 0x91
|
|
(op) => {
|
|
throw new NotImplementedException("0x91");
|
|
},
|
|
// 0x92
|
|
(op) => {
|
|
throw new NotImplementedException("0x92");
|
|
},
|
|
// 0x93
|
|
(op) => {
|
|
throw new NotImplementedException("0x93");
|
|
},
|
|
// 0x94
|
|
(op) => {
|
|
throw new NotImplementedException("0x94");
|
|
},
|
|
// 0x95
|
|
(op) => {
|
|
throw new NotImplementedException("0x95");
|
|
},
|
|
// 0x96
|
|
(op) => {
|
|
throw new NotImplementedException("0x96");
|
|
},
|
|
// 0x97
|
|
(op) => {
|
|
throw new NotImplementedException("0x97");
|
|
},
|
|
// 0x98
|
|
(op) => {
|
|
throw new NotImplementedException("0x98");
|
|
},
|
|
// 0x99
|
|
(op) => {
|
|
throw new NotImplementedException("0x99");
|
|
},
|
|
// 0x9A
|
|
(op) => {
|
|
throw new NotImplementedException("0x9A");
|
|
},
|
|
// 0x9B
|
|
(op) => {
|
|
throw new NotImplementedException("0x9B");
|
|
},
|
|
// 0x9C
|
|
(op) => {
|
|
throw new NotImplementedException("0x9C");
|
|
},
|
|
// 0x9D
|
|
(op) => {
|
|
throw new NotImplementedException("0x9D");
|
|
},
|
|
// 0x9E
|
|
(op) => {
|
|
throw new NotImplementedException("0x9E");
|
|
},
|
|
// 0x9F
|
|
(op) => {
|
|
throw new NotImplementedException("0x9F");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xA0-0xAF
|
|
// 0xA0
|
|
(op) => {
|
|
throw new NotImplementedException("0xA0");
|
|
},
|
|
// 0xA1
|
|
(op) => {
|
|
throw new NotImplementedException("0xA1");
|
|
},
|
|
// 0xA2
|
|
(op) => {
|
|
throw new NotImplementedException("0xA2");
|
|
},
|
|
// 0xA3
|
|
(op) => {
|
|
throw new NotImplementedException("0xA3");
|
|
},
|
|
// 0xA4
|
|
(op) => {
|
|
throw new NotImplementedException("0xA4");
|
|
},
|
|
// 0xA5
|
|
(op) => {
|
|
throw new NotImplementedException("0xA5");
|
|
},
|
|
// 0xA6
|
|
(op) => {
|
|
throw new NotImplementedException("0xA6");
|
|
},
|
|
// 0xA7
|
|
(op) => {
|
|
throw new NotImplementedException("0xA7");
|
|
},
|
|
// 0xA8
|
|
(op) => {
|
|
throw new NotImplementedException("0xA8");
|
|
},
|
|
// 0xA9
|
|
(op) => {
|
|
throw new NotImplementedException("0xA9");
|
|
},
|
|
// 0xAA
|
|
(op) => {
|
|
throw new NotImplementedException("0xAA");
|
|
},
|
|
// 0xAB
|
|
(op) => {
|
|
throw new NotImplementedException("0xAB");
|
|
},
|
|
// 0xAC
|
|
(op) => {
|
|
throw new NotImplementedException("0xAC");
|
|
},
|
|
// 0xAD
|
|
(op) => {
|
|
throw new NotImplementedException("0xAD");
|
|
},
|
|
// 0xAE
|
|
(op) => {
|
|
throw new NotImplementedException("0xAE");
|
|
},
|
|
// 0xAF
|
|
(op) => {
|
|
throw new NotImplementedException("0xAF");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xB0-0xBF
|
|
// 0xB0
|
|
(op) => {
|
|
throw new NotImplementedException("0xB0");
|
|
},
|
|
// 0xB1
|
|
(op) => {
|
|
throw new NotImplementedException("0xB1");
|
|
},
|
|
// 0xB2
|
|
(op) => {
|
|
throw new NotImplementedException("0xB2");
|
|
},
|
|
// 0xB3
|
|
(op) => {
|
|
throw new NotImplementedException("0xB3");
|
|
},
|
|
// 0xB4
|
|
(op) => {
|
|
throw new NotImplementedException("0xB4");
|
|
},
|
|
// 0xB5
|
|
(op) => {
|
|
throw new NotImplementedException("0xB5");
|
|
},
|
|
// 0xB6
|
|
(op) => {
|
|
throw new NotImplementedException("0xB6");
|
|
},
|
|
// 0xB7
|
|
(op) => {
|
|
throw new NotImplementedException("0xB7");
|
|
},
|
|
// 0xB8
|
|
(op) => {
|
|
throw new NotImplementedException("0xB8");
|
|
},
|
|
// 0xB9
|
|
(op) => {
|
|
throw new NotImplementedException("0xB9");
|
|
},
|
|
// 0xBA
|
|
(op) => {
|
|
throw new NotImplementedException("0xBA");
|
|
},
|
|
// 0xBB
|
|
(op) => {
|
|
throw new NotImplementedException("0xBB");
|
|
},
|
|
// 0xBC
|
|
(op) => {
|
|
throw new NotImplementedException("0xBC");
|
|
},
|
|
// 0xBD
|
|
(op) => {
|
|
throw new NotImplementedException("0xBD");
|
|
},
|
|
// 0xBE
|
|
(op) => {
|
|
throw new NotImplementedException("0xBE");
|
|
},
|
|
// 0xBF
|
|
(op) => {
|
|
throw new NotImplementedException("0xBF");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xC0-0xCF
|
|
// 0xC0
|
|
(op) => {
|
|
throw new NotImplementedException("0xC0");
|
|
},
|
|
// 0xC1
|
|
(op) => {
|
|
throw new NotImplementedException("0xC1");
|
|
},
|
|
// 0xC2
|
|
(op) => {
|
|
throw new NotImplementedException("0xC2");
|
|
},
|
|
// 0xC3
|
|
(op) => {
|
|
throw new NotImplementedException("0xC3");
|
|
},
|
|
// 0xC4
|
|
(op) => {
|
|
throw new NotImplementedException("0xC4");
|
|
},
|
|
// 0xC5
|
|
(op) => {
|
|
throw new NotImplementedException("0xC5");
|
|
},
|
|
// 0xC6
|
|
(op) => {
|
|
throw new NotImplementedException("0xC6");
|
|
},
|
|
// 0xC7
|
|
(op) => {
|
|
throw new NotImplementedException("0xC7");
|
|
},
|
|
// 0xC8
|
|
(op) => {
|
|
throw new NotImplementedException("0xC8");
|
|
},
|
|
// 0xC9
|
|
(op) => {
|
|
throw new NotImplementedException("0xC9");
|
|
},
|
|
// 0xCA
|
|
(op) => {
|
|
throw new NotImplementedException("0xCA");
|
|
},
|
|
// 0xCB
|
|
(op) => {
|
|
throw new NotImplementedException("0xCB");
|
|
},
|
|
// 0xCC
|
|
(op) => {
|
|
throw new NotImplementedException("0xCC");
|
|
},
|
|
// 0xCD
|
|
(op) => {
|
|
throw new NotImplementedException("0xCD");
|
|
},
|
|
// 0xCE
|
|
(op) => {
|
|
throw new NotImplementedException("0xCE");
|
|
},
|
|
// 0xCF
|
|
(op) => {
|
|
throw new NotImplementedException("0xCF");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xD0-0xDF
|
|
// 0xD0
|
|
(op) => {
|
|
throw new NotImplementedException("0xD0");
|
|
},
|
|
// 0xD1
|
|
(op) => {
|
|
throw new NotImplementedException("0xD1");
|
|
},
|
|
// 0xD2
|
|
(op) => {
|
|
throw new NotImplementedException("0xD2");
|
|
},
|
|
// 0xD3
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xD4
|
|
(op) => {
|
|
throw new NotImplementedException("0xD4");
|
|
},
|
|
// 0xD5
|
|
(op) => {
|
|
throw new NotImplementedException("0xD5");
|
|
},
|
|
// 0xD6
|
|
(op) => {
|
|
throw new NotImplementedException("0xD6");
|
|
},
|
|
// 0xD7
|
|
(op) => {
|
|
throw new NotImplementedException("0xD7");
|
|
},
|
|
// 0xD8
|
|
(op) => {
|
|
throw new NotImplementedException("0xD8");
|
|
},
|
|
// 0xD9
|
|
(op) => {
|
|
throw new NotImplementedException("0xD9");
|
|
},
|
|
// 0xDA
|
|
(op) => {
|
|
throw new NotImplementedException("0xDA");
|
|
},
|
|
// 0xDB
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xDC
|
|
(op) => {
|
|
throw new NotImplementedException("0xDC");
|
|
},
|
|
// 0xDD
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xDE
|
|
(op) => {
|
|
throw new NotImplementedException("0xDE");
|
|
},
|
|
// 0xDF
|
|
(op) => {
|
|
throw new NotImplementedException("0xDF");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xE0-0xEF
|
|
// 0xE0
|
|
(op) => {
|
|
throw new NotImplementedException("0xE0");
|
|
},
|
|
// 0xE1
|
|
(op) => {
|
|
throw new NotImplementedException("0xE1");
|
|
},
|
|
// 0xE2
|
|
(op) => {
|
|
throw new NotImplementedException("0xE2");
|
|
},
|
|
// 0xE3
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xE4
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xE5
|
|
(op) => {
|
|
throw new NotImplementedException("0xE5");
|
|
},
|
|
// 0xE6
|
|
(op) => {
|
|
throw new NotImplementedException("0xE6");
|
|
},
|
|
// 0xE7
|
|
(op) => {
|
|
throw new NotImplementedException("0xE7");
|
|
},
|
|
// 0xE8
|
|
(op) => {
|
|
throw new NotImplementedException("0xE8");
|
|
},
|
|
// 0xE9
|
|
(op) => {
|
|
throw new NotImplementedException("0xE9");
|
|
},
|
|
// 0xEA
|
|
(op) => {
|
|
throw new NotImplementedException("0xEA");
|
|
},
|
|
// 0xEB
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xEC
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xED
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xEE
|
|
(op) => {
|
|
throw new NotImplementedException("0xEE");
|
|
},
|
|
// 0xEF
|
|
(op) => {
|
|
throw new NotImplementedException("0xEF");
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xF0-0xFF
|
|
// 0xF0
|
|
(op) => {
|
|
throw new NotImplementedException("0xF0");
|
|
},
|
|
// 0xF1
|
|
(op) => {
|
|
throw new NotImplementedException("0xF1");
|
|
},
|
|
// 0xF2
|
|
(op) => {
|
|
throw new NotImplementedException("0xF2");
|
|
},
|
|
// 0xF3
|
|
(op) => {
|
|
throw new NotImplementedException("0xF3");
|
|
},
|
|
// 0xF4
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xF5
|
|
(op) => {
|
|
throw new NotImplementedException("0xF5");
|
|
},
|
|
// 0xF6
|
|
(op) => {
|
|
throw new NotImplementedException("0xF6");
|
|
},
|
|
// 0xF7
|
|
(op) => {
|
|
throw new NotImplementedException("0xF7");
|
|
},
|
|
// 0xF8
|
|
(op) => {
|
|
throw new NotImplementedException("0xF8");
|
|
},
|
|
// 0xF9
|
|
(op) => {
|
|
throw new NotImplementedException("0xF9");
|
|
},
|
|
// 0xFA
|
|
(op) => {
|
|
throw new NotImplementedException("0xFA");
|
|
},
|
|
// 0xFB
|
|
(op) => {
|
|
throw new NotImplementedException("0xFB");
|
|
},
|
|
// 0xFC
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xFD
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xFE
|
|
(op) => {
|
|
throw new NotImplementedException("0xFE");
|
|
},
|
|
// 0xFF
|
|
(op) => {
|
|
throw new NotImplementedException("0xFF");
|
|
}
|
|
#endregion
|
|
#endregion
|
|
};
|
|
}
|
|
|
|
private byte IncrementRegister(byte register)
|
|
{
|
|
byte reg = (byte)(register + 1);
|
|
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.Zero = reg == 0;
|
|
// This logic only works for the increment operation
|
|
registers.Flags.HalfCarry = reg == 16;
|
|
|
|
registers.PC += 1;
|
|
return reg;
|
|
}
|
|
|
|
private byte DecrementRegister(byte register)
|
|
{
|
|
byte reg = (byte)((uint)register - 1);
|
|
|
|
registers.Flags.Subtract = true;
|
|
registers.Flags.Zero = reg == 0;
|
|
// This logic only works for the decrement operation
|
|
registers.Flags.HalfCarry = reg == 15;
|
|
|
|
registers.PC += 1;
|
|
return reg;
|
|
}
|
|
|
|
private ushort AddWideRegisters(ushort wideRegister1, ushort wideRegister2)
|
|
{
|
|
// ADD HL, BC
|
|
registers.Flags.Subtract = false;
|
|
registers.Flags.HalfCarry = (((wideRegister1 & 0x0FFF) + (wideRegister2 & 0x0FFF) & 0x1000) == 0x1000);
|
|
registers.Flags.Carry = (((wideRegister1 + wideRegister2) & 0x10000) == 0x10000);
|
|
|
|
registers.PC += 1;
|
|
|
|
return (ushort)(wideRegister1 + wideRegister2);
|
|
}
|
|
}
|
|
|
|
|
|
[Serializable]
|
|
public class IllegalInstructionException : Exception
|
|
{
|
|
public OpCode OpCode { get; set; }
|
|
public IllegalInstructionException() { }
|
|
public IllegalInstructionException(OpCode opCode, string message) : base(message)
|
|
{
|
|
OpCode = opCode;
|
|
}
|
|
public IllegalInstructionException(string message) : base(message) { }
|
|
public IllegalInstructionException(string message, Exception inner) : base(message, inner) { }
|
|
protected IllegalInstructionException(
|
|
System.Runtime.Serialization.SerializationInfo info,
|
|
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
|
}
|
|
}
|