Files
MCEmuCore/MCEmuCore.GBMonolith/Cpu.cs

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) { }
}
}