From 718ea88dea12822a84e598a7b14573fc3a9315b1 Mon Sep 17 00:00:00 2001 From: Mikah Chapman Date: Sun, 17 May 2020 21:47:58 -0600 Subject: [PATCH] Implement 0x10-0x1F instructions --- MCEmuCore.GBMonolith/Cpu.cs | 1732 ++++++++++++++++++----------------- 1 file changed, 904 insertions(+), 828 deletions(-) diff --git a/MCEmuCore.GBMonolith/Cpu.cs b/MCEmuCore.GBMonolith/Cpu.cs index 9bee114..dd0b75a 100644 --- a/MCEmuCore.GBMonolith/Cpu.cs +++ b/MCEmuCore.GBMonolith/Cpu.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace MCEmuCore.GBMonolith { @@ -15,30 +16,29 @@ namespace MCEmuCore.GBMonolith private readonly CpuRegisters registers; #region OpCodes - private readonly Dictionary> OpCodeTable; - private readonly Func[] OpCodeArray; + private readonly List> OpCodeArray; #endregion public Cpu() { registers = new CpuRegisters(); - OpCodeTable = new Dictionary>() + OpCodeArray = new List>() { #region OpCodes #region OpCodes 0x00-0x0F - {0x00, (op) =>{ + // 0x00 + (op) => { // NOP registers.PC += 1; return 4; - } }, - {0x01, (op) => - { + }, + // 0x01 + (op) => { // LD BC,d16 if (op.Arg1.HasValue && op.Arg2.HasValue) { - ushort operand = (ushort)(op.Arg2 + (op.Arg1 << 8)); - registers.BC = operand; + registers.BC = (ushort)(op.Arg2 + (op.Arg1 << 8)); registers.PC += 3; return 12; } @@ -46,48 +46,34 @@ namespace MCEmuCore.GBMonolith { throw new IllegalInstructionException(op, "Missing arguments for LD BC"); } - } }, - {0x02, (op) => - { + }, + // 0x02 + (op) => { // LD (BC), A throw new NotImplementedException("LD (BC), A"); - } }, - {0x03, (op) => - { + }, + // 0x03 + (op) => { registers.BC += 1; registers.PC += 1; return 8; - } }, - {0x04, (op) => - { + }, + // 0x04 + (op) => { // INC B - byte reg = (byte)(registers.B + 1); - registers.B = reg; + registers.B = IncrementRegister(registers.B); - 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 4; - } }, - {0x05, (op) => - { + }, + // 0x05 + (op) => { // DEC B - byte reg = (byte)((uint)registers.B - 1); - registers.B = reg; + registers.B = DecrementRegister(registers.B); - 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 4; - } }, - {0x06, (op) => - { + }, + // 0x06 + (op) => { // LD B,d8 if (op.Arg1.HasValue) { @@ -99,9 +85,9 @@ namespace MCEmuCore.GBMonolith { throw new IllegalInstructionException(op, "Missing arguments for LD B"); } - } }, - {0x07, (op) => - { + }, + // 0x07 + (op) => { // RLCA registers.Flags.Zero = false; registers.Flags.Subtract = false; @@ -111,68 +97,49 @@ namespace MCEmuCore.GBMonolith registers.A = (byte)((registers.A << 1) + (registers.A >> 7)); registers.PC += 1; return 4; - } }, - {0x08, (op) => - { + }, + // 0x08 + (op) => { // LD (a16), SP // Load SP into address throw new NotImplementedException("LD (a16), SP"); - } }, - {0x09, (op) => - { + }, + // 0x09 + (op) => { // ADD HL, BC - registers.Flags.Subtract = false; - registers.Flags.HalfCarry = (((registers.HL & 0x0FFF) + (registers.BC & 0x0FFF) & 0x1000) == 0x1000); - registers.Flags.Carry = (((registers.HL + registers.BC) & 0x10000) == 0x10000); - - registers.HL += registers.BC; - registers.PC += 1; + registers.HL = AddWideRegisters(registers.HL, registers.BC); return 8; - } }, - {0x0A, (op) => - { + }, + // 0x0A + (op) => { // LD A, (BC) // Load byte at address stored in BC into A throw new NotImplementedException("LD A, (BC)"); - } }, - {0x0B, (op) => - { + }, + // 0x0B + (op) => { // DEC BC registers.BC -= 1; registers.PC += 1; return 8; - } }, - {0x0C, (op) => - { + }, + // 0x0C + (op) => { // INC C - byte reg = (byte)(registers.C + 1); - registers.C = reg; + registers.C = IncrementRegister(registers.C); - 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 4; - } }, - {0x0D, (op) => - { + }, + // 0x0D + (op) => { // DEC C - byte reg = (byte)((uint)registers.C - 1); - registers.C = reg; + registers.C = DecrementRegister(registers.C); - 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 4; - } }, - {0x0E, (op) => - { + }, + // 0x0E + (op) => { // LD C,d8 if (op.Arg1.HasValue) { @@ -184,9 +151,9 @@ namespace MCEmuCore.GBMonolith { throw new IllegalInstructionException(op, "Missing argument for LD B"); } - } }, - {0x0F, (op) => - { + }, + // 0x0F + (op) => { // RRCA registers.Flags.Zero = false; registers.Flags.Subtract = false; @@ -196,1009 +163,1118 @@ namespace MCEmuCore.GBMonolith registers.A = (byte)((registers.A >> 1) + (registers.A << 7)); registers.PC += 1; return 4; - } }, + }, #endregion #region OpCodes 0x10-0x1F - {0x10, (op) => - { + // 0x10 + (op) => { // STOP 0 // Halts CPU & LCD until button pressed throw new NotImplementedException("STOP"); - } }, - {0x11, (op) => - { + }, + // 0x11 + (op) => { // LD DE, d16 - throw new NotImplementedException("0x11"); - } }, - {0x12, (op) => - { + 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 - throw new NotImplementedException("0x13"); - } }, - {0x14, (op) => - { - throw new NotImplementedException("0x14"); - } }, - {0x15, (op) => - { - throw new NotImplementedException("0x15"); - } }, - {0x16, (op) => - { - throw new NotImplementedException("0x16"); - } }, - {0x17, (op) => - { - throw new NotImplementedException("0x17"); - } }, - {0x18, (op) => - { - throw new NotImplementedException("0x18"); - } }, - {0x19, (op) => - { - throw new NotImplementedException("0x19"); - } }, - {0x1A, (op) => - { - throw new NotImplementedException("0x1A"); - } }, - {0x1B, (op) => - { - throw new NotImplementedException("0x1B"); - } }, - {0x1C, (op) => - { - throw new NotImplementedException("0c1C"); - } }, - {0x1D, (op) => - { - throw new NotImplementedException("0x1D"); - } }, - {0x1E, (op) => - { - throw new NotImplementedException("0x1E"); - } }, - {0x1F, (op) => - { - throw new NotImplementedException("0x1F"); - } }, + }, + // 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) => - { + // 0x20 + (op) => { throw new NotImplementedException("0x20"); - } }, - {0x21, (op) => - { + }, + // 0x21 + (op) => { throw new NotImplementedException("0x21"); - } }, - {0x22, (op) => - { + }, + // 0x22 + (op) => { throw new NotImplementedException("0x22"); - } }, - {0x23, (op) => - { + }, + // 0x23 + (op) => { throw new NotImplementedException("0x23"); - } }, - {0x24, (op) => - { + }, + // 0x24 + (op) => { throw new NotImplementedException("0x24"); - } }, - {0x25, (op) => - { + }, + // 0x25 + (op) => { throw new NotImplementedException("0x25"); - } }, - {0x26, (op) => - { + }, + // 0x26 + (op) => { throw new NotImplementedException("0x26"); - } }, - {0x27, (op) => - { + }, + // 0x27 + (op) => { throw new NotImplementedException("0x27"); - } }, - {0x28, (op) => - { + }, + // 0x28 + (op) => { throw new NotImplementedException("0x28"); - } }, - {0x29, (op) => - { + }, + // 0x29 + (op) => { throw new NotImplementedException("0x29"); - } }, - {0x2A, (op) => - { + }, + // 0x2A + (op) => { throw new NotImplementedException("0x2A"); - } }, - {0x2B, (op) => - { + }, + // 0x2B + (op) => { throw new NotImplementedException("0x2B"); - } }, - {0x2C, (op) => - { + }, + // 0x2C + (op) => { throw new NotImplementedException("0x2C"); - } }, - {0x2D, (op) => - { + }, + // 0x2D + (op) => { throw new NotImplementedException("0x2D"); - } }, - {0x2E, (op) => - { + }, + // 0x2E + (op) => { throw new NotImplementedException("0x2E"); - } }, - {0x2F, (op) => - { + }, + // 0x2F + (op) => { throw new NotImplementedException("0x2F"); - } }, + }, #endregion #region OpCodes 0x30-0x3F - {0x30, (op) => - { + // 0x30 + (op) => { throw new NotImplementedException("0x30"); - } }, - {0x31, (op) => - { + }, + // 0x31 + (op) => { throw new NotImplementedException("0x31"); - } }, - {0x32, (op) => - { + }, + // 0x32 + (op) => { throw new NotImplementedException("0x32"); - } }, - {0x33, (op) => - { + }, + // 0x33 + (op) => { throw new NotImplementedException("0x33"); - } }, - {0x34, (op) => - { + }, + // 0x34 + (op) => { throw new NotImplementedException("0x34"); - } }, - {0x35, (op) => - { + }, + // 0x35 + (op) => { throw new NotImplementedException("0x35"); - } }, - {0x36, (op) => - { + }, + // 0x36 + (op) => { throw new NotImplementedException("0x36"); - } }, - {0x37, (op) => - { + }, + // 0x37 + (op) => { throw new NotImplementedException("0x37"); - } }, - {0x38, (op) => - { + }, + // 0x38 + (op) => { throw new NotImplementedException("0x38"); - } }, - {0x39, (op) => - { + }, + // 0x39 + (op) => { throw new NotImplementedException("0x39"); - } }, - {0x3A, (op) => - { + }, + // 0x3A + (op) => { throw new NotImplementedException("0x3A"); - } }, - {0x3B, (op) => - { + }, + // 0x3B + (op) => { throw new NotImplementedException("0x3B"); - } }, - {0x3C, (op) => - { + }, + // 0x3C + (op) => { throw new NotImplementedException("0x3C"); - } }, - {0x3D, (op) => - { + }, + // 0x3D + (op) => { throw new NotImplementedException("0x3D"); - } }, - {0x3E, (op) => - { + }, + // 0x3E + (op) => { throw new NotImplementedException("0x3E"); - } }, - {0x3F, (op) => - { + }, + // 0x3F + (op) => { throw new NotImplementedException("0x3F"); - } }, + }, #endregion #region OpCodes 0x40-0x4F - {0x40, (op) => - { + // 0x40 + (op) => { throw new NotImplementedException("0x40"); - } }, - {0x41, (op) => - { + }, + // 0x41 + (op) => { throw new NotImplementedException("0x41"); - } }, - {0x42, (op) => - { + }, + // 0x42 + (op) => { throw new NotImplementedException("0x42"); - } }, - {0x43, (op) => - { + }, + // 0x43 + (op) => { throw new NotImplementedException("0x43"); - } }, - {0x44, (op) => - { + }, + // 0x44 + (op) => { throw new NotImplementedException("0x44"); - } }, - {0x45, (op) => - { + }, + // 0x45 + (op) => { throw new NotImplementedException("0x45"); - } }, - {0x46, (op) => - { + }, + // 0x46 + (op) => { throw new NotImplementedException("0x46"); - } }, - {0x47, (op) => - { + }, + // 0x47 + (op) => { throw new NotImplementedException("0x47"); - } }, - {0x48, (op) => - { + }, + // 0x48 + (op) => { throw new NotImplementedException("0x48"); - } }, - {0x49, (op) => - { + }, + // 0x49 + (op) => { throw new NotImplementedException("0x49"); - } }, - {0x4A, (op) => - { + }, + // 0x4A + (op) => { throw new NotImplementedException("0x4A"); - } }, - {0x4B, (op) => - { + }, + // 0x4B + (op) => { throw new NotImplementedException("0x4B"); - } }, - {0x4C, (op) => - { + }, + // 0x4C + (op) => { throw new NotImplementedException("0x4C"); - } }, - {0x4D, (op) => - { + }, + // 0x4D + (op) => { throw new NotImplementedException("0x4D"); - } }, - {0x4E, (op) => - { + }, + // 0x4E + (op) => { throw new NotImplementedException("0x4E"); - } }, - {0x4F, (op) => - { + }, + // 0x4F + (op) => { throw new NotImplementedException("0x4F"); - } }, + }, #endregion #region OpCodes 0x50-0x5F - {0x50, (op) => - { + // 0x50 + (op) => { throw new NotImplementedException("0x50"); - } }, - {0x51, (op) => - { + }, + // 0x51 + (op) => { throw new NotImplementedException("0x51"); - } }, - {0x52, (op) => - { + }, + // 0x52 + (op) => { throw new NotImplementedException("0x52"); - } }, - {0x53, (op) => - { + }, + // 0x53 + (op) => { throw new NotImplementedException("0x53"); - } }, - {0x54, (op) => - { + }, + // 0x54 + (op) => { throw new NotImplementedException("0x54"); - } }, - {0x55, (op) => - { + }, + // 0x55 + (op) => { throw new NotImplementedException("0x55"); - } }, - {0x56, (op) => - { + }, + // 0x56 + (op) => { throw new NotImplementedException("0x56"); - } }, - {0x57, (op) => - { + }, + // 0x57 + (op) => { throw new NotImplementedException("0x57"); - } }, - {0x58, (op) => - { + }, + // 0x58 + (op) => { throw new NotImplementedException("0x58"); - } }, - {0x59, (op) => - { + }, + // 0x59 + (op) => { throw new NotImplementedException("0x59"); - } }, - {0x5A, (op) => - { + }, + // 0x5A + (op) => { throw new NotImplementedException("0x5A"); - } }, - {0x5B, (op) => - { + }, + // 0x5B + (op) => { throw new NotImplementedException("0x5B"); - } }, - {0x5C, (op) => - { + }, + // 0x5C + (op) => { throw new NotImplementedException("0x5C"); - } }, - {0x5D, (op) => - { + }, + // 0x5D + (op) => { throw new NotImplementedException("0x5D"); - } }, - {0x5E, (op) => - { + }, + // 0x5E + (op) => { throw new NotImplementedException("0x5E"); - } }, - {0x5F, (op) => - { + }, + // 0x5F + (op) => { throw new NotImplementedException("0x5F"); - } }, + }, #endregion #region OpCodes 0x60-0x6F - {0x60, (op) => - { + // 0x60 + (op) => { throw new NotImplementedException("0x60"); - } }, - {0x61, (op) => - { + }, + // 0x61 + (op) => { throw new NotImplementedException("0x61"); - } }, - {0x62, (op) => - { + }, + // 0x62 + (op) => { throw new NotImplementedException("0x62"); - } }, - {0x63, (op) => - { + }, + // 0x63 + (op) => { throw new NotImplementedException("0x63"); - } }, - {0x64, (op) => - { + }, + // 0x64 + (op) => { throw new NotImplementedException("0x64"); - } }, - {0x65, (op) => - { + }, + // 0x65 + (op) => { throw new NotImplementedException("0x65"); - } }, - {0x66, (op) => - { + }, + // 0x66 + (op) => { throw new NotImplementedException("0x66"); - } }, - {0x67, (op) => - { + }, + // 0x67 + (op) => { throw new NotImplementedException("0x67"); - } }, - {0x68, (op) => - { + }, + // 0x68 + (op) => { throw new NotImplementedException("0x68"); - } }, - {0x69, (op) => - { + }, + // 0x69 + (op) => { throw new NotImplementedException("0x69"); - } }, - {0x6A, (op) => - { + }, + // 0x6A + (op) => { throw new NotImplementedException("0x6A"); - } }, - {0x6B, (op) => - { + }, + // 0x6B + (op) => { throw new NotImplementedException("0x6B"); - } }, - {0x6C, (op) => - { + }, + // 0x6C + (op) => { throw new NotImplementedException("0x6C"); - } }, - {0x6D, (op) => - { + }, + // 0x6D + (op) => { throw new NotImplementedException("0x6D"); - } }, - {0x6E, (op) => - { + }, + // 0x6E + (op) => { throw new NotImplementedException("0x6E"); - } }, - {0x6F, (op) => - { + }, + // 0x6F + (op) => { throw new NotImplementedException("0x6F"); - } }, + }, #endregion #region OpCodes 0x70-0x7F - {0x70, (op) => - { + // 0x70 + (op) => { throw new NotImplementedException("0x70"); - } }, - {0x71, (op) => - { + }, + // 0x71 + (op) => { throw new NotImplementedException("0x71"); - } }, - {0x72, (op) => - { + }, + // 0x72 + (op) => { throw new NotImplementedException("0x72"); - } }, - {0x73, (op) => - { + }, + // 0x73 + (op) => { throw new NotImplementedException("0x73"); - } }, - {0x74, (op) => - { + }, + // 0x74 + (op) => { throw new NotImplementedException("0x74"); - } }, - {0x75, (op) => - { + }, + // 0x75 + (op) => { throw new NotImplementedException("0x75"); - } }, - {0x76, (op) => - { + }, + // 0x76 + (op) => { throw new NotImplementedException("0x76"); - } }, - {0x77, (op) => - { + }, + // 0x77 + (op) => { throw new NotImplementedException("0x77"); - } }, - {0x78, (op) => - { + }, + // 0x78 + (op) => { throw new NotImplementedException("0x78"); - } }, - {0x79, (op) => - { + }, + // 0x79 + (op) => { throw new NotImplementedException("0x79"); - } }, - {0x7A, (op) => - { + }, + // 0x7A + (op) => { throw new NotImplementedException("0x7A"); - } }, - {0x7B, (op) => - { + }, + // 0x7B + (op) => { throw new NotImplementedException("0x7B"); - } }, - {0x7C, (op) => - { + }, + // 0x7C + (op) => { throw new NotImplementedException("0x7C"); - } }, - {0x7D, (op) => - { + }, + // 0x7D + (op) => { throw new NotImplementedException("0x7D"); - } }, - {0x7E, (op) => - { + }, + // 0x7E + (op) => { throw new NotImplementedException("0x7E"); - } }, - {0x7F, (op) => - { + }, + // 0x7F + (op) => { throw new NotImplementedException("0x7F"); - } }, + }, #endregion #region OpCodes 0x80-0x8F - {0x80, (op) => - { + // 0x80 + (op) => { throw new NotImplementedException("0x80"); - } }, - {0x81, (op) => - { + }, + // 0x81 + (op) => { throw new NotImplementedException("0x81"); - } }, - {0x82, (op) => - { + }, + // 0x82 + (op) => { throw new NotImplementedException("0x82"); - } }, - {0x83, (op) => - { + }, + // 0x83 + (op) => { throw new NotImplementedException("0x83"); - } }, - {0x84, (op) => - { + }, + // 0x84 + (op) => { throw new NotImplementedException("0x84"); - } }, - {0x85, (op) => - { + }, + // 0x85 + (op) => { throw new NotImplementedException("0x85"); - } }, - {0x86, (op) => - { + }, + // 0x86 + (op) => { throw new NotImplementedException("0x86"); - } }, - {0x87, (op) => - { + }, + // 0x87 + (op) => { throw new NotImplementedException("0x87"); - } }, - {0x88, (op) => - { + }, + // 0x88 + (op) => { throw new NotImplementedException("0x88"); - } }, - {0x89, (op) => - { + }, + // 0x89 + (op) => { throw new NotImplementedException("0x89"); - } }, - {0x8A, (op) => - { + }, + // 0x8A + (op) => { throw new NotImplementedException("0x8A"); - } }, - {0x8B, (op) => - { + }, + // 0x8B + (op) => { throw new NotImplementedException("0x8B"); - } }, - {0x8C, (op) => - { + }, + // 0x8C + (op) => { throw new NotImplementedException("0x8C"); - } }, - {0x8D, (op) => - { + }, + // 0x8D + (op) => { throw new NotImplementedException("0x8D"); - } }, - {0x8E, (op) => - { + }, + // 0x8E + (op) => { throw new NotImplementedException("0x8E"); - } }, - {0x8F, (op) => - { + }, + // 0x8F + (op) => { throw new NotImplementedException("0x8F"); - } }, + }, #endregion #region OpCodes 0x90-0x9F - {0x90, (op) => - { + // 0x90 + (op) => { throw new NotImplementedException("0x90"); - } }, - {0x91, (op) => - { + }, + // 0x91 + (op) => { throw new NotImplementedException("0x91"); - } }, - {0x92, (op) => - { + }, + // 0x92 + (op) => { throw new NotImplementedException("0x92"); - } }, - {0x93, (op) => - { + }, + // 0x93 + (op) => { throw new NotImplementedException("0x93"); - } }, - {0x94, (op) => - { + }, + // 0x94 + (op) => { throw new NotImplementedException("0x94"); - } }, - {0x95, (op) => - { + }, + // 0x95 + (op) => { throw new NotImplementedException("0x95"); - } }, - {0x96, (op) => - { + }, + // 0x96 + (op) => { throw new NotImplementedException("0x96"); - } }, - {0x97, (op) => - { + }, + // 0x97 + (op) => { throw new NotImplementedException("0x97"); - } }, - {0x98, (op) => - { + }, + // 0x98 + (op) => { throw new NotImplementedException("0x98"); - } }, - {0x99, (op) => - { + }, + // 0x99 + (op) => { throw new NotImplementedException("0x99"); - } }, - {0x9A, (op) => - { + }, + // 0x9A + (op) => { throw new NotImplementedException("0x9A"); - } }, - {0x9B, (op) => - { + }, + // 0x9B + (op) => { throw new NotImplementedException("0x9B"); - } }, - {0x9C, (op) => - { + }, + // 0x9C + (op) => { throw new NotImplementedException("0x9C"); - } }, - {0x9D, (op) => - { + }, + // 0x9D + (op) => { throw new NotImplementedException("0x9D"); - } }, - {0x9E, (op) => - { + }, + // 0x9E + (op) => { throw new NotImplementedException("0x9E"); - } }, - {0x9F, (op) => - { + }, + // 0x9F + (op) => { throw new NotImplementedException("0x9F"); - } }, + }, #endregion #region OpCodes 0xA0-0xAF - {0xA0, (op) => - { + // 0xA0 + (op) => { throw new NotImplementedException("0xA0"); - } }, - {0xA1, (op) => - { + }, + // 0xA1 + (op) => { throw new NotImplementedException("0xA1"); - } }, - {0xA2, (op) => - { + }, + // 0xA2 + (op) => { throw new NotImplementedException("0xA2"); - } }, - {0xA3, (op) => - { + }, + // 0xA3 + (op) => { throw new NotImplementedException("0xA3"); - } }, - {0xA4, (op) => - { + }, + // 0xA4 + (op) => { throw new NotImplementedException("0xA4"); - } }, - {0xA5, (op) => - { + }, + // 0xA5 + (op) => { throw new NotImplementedException("0xA5"); - } }, - {0xA6, (op) => - { + }, + // 0xA6 + (op) => { throw new NotImplementedException("0xA6"); - } }, - {0xA7, (op) => - { + }, + // 0xA7 + (op) => { throw new NotImplementedException("0xA7"); - } }, - {0xA8, (op) => - { + }, + // 0xA8 + (op) => { throw new NotImplementedException("0xA8"); - } }, - {0xA9, (op) => - { + }, + // 0xA9 + (op) => { throw new NotImplementedException("0xA9"); - } }, - {0xAA, (op) => - { + }, + // 0xAA + (op) => { throw new NotImplementedException("0xAA"); - } }, - {0xAB, (op) => - { + }, + // 0xAB + (op) => { throw new NotImplementedException("0xAB"); - } }, - {0xAC, (op) => - { + }, + // 0xAC + (op) => { throw new NotImplementedException("0xAC"); - } }, - {0xAD, (op) => - { + }, + // 0xAD + (op) => { throw new NotImplementedException("0xAD"); - } }, - {0xAE, (op) => - { + }, + // 0xAE + (op) => { throw new NotImplementedException("0xAE"); - } }, - {0xAF, (op) => - { + }, + // 0xAF + (op) => { throw new NotImplementedException("0xAF"); - } }, + }, #endregion #region OpCodes 0xB0-0xBF - {0xB0, (op) => - { + // 0xB0 + (op) => { throw new NotImplementedException("0xB0"); - } }, - {0xB1, (op) => - { + }, + // 0xB1 + (op) => { throw new NotImplementedException("0xB1"); - } }, - {0xB2, (op) => - { + }, + // 0xB2 + (op) => { throw new NotImplementedException("0xB2"); - } }, - {0xB3, (op) => - { + }, + // 0xB3 + (op) => { throw new NotImplementedException("0xB3"); - } }, - {0xB4, (op) => - { + }, + // 0xB4 + (op) => { throw new NotImplementedException("0xB4"); - } }, - {0xB5, (op) => - { + }, + // 0xB5 + (op) => { throw new NotImplementedException("0xB5"); - } }, - {0xB6, (op) => - { + }, + // 0xB6 + (op) => { throw new NotImplementedException("0xB6"); - } }, - {0xB7, (op) => - { + }, + // 0xB7 + (op) => { throw new NotImplementedException("0xB7"); - } }, - {0xB8, (op) => - { + }, + // 0xB8 + (op) => { throw new NotImplementedException("0xB8"); - } }, - {0xB9, (op) => - { + }, + // 0xB9 + (op) => { throw new NotImplementedException("0xB9"); - } }, - {0xBA, (op) => - { + }, + // 0xBA + (op) => { throw new NotImplementedException("0xBA"); - } }, - {0xBB, (op) => - { + }, + // 0xBB + (op) => { throw new NotImplementedException("0xBB"); - } }, - {0xBC, (op) => - { + }, + // 0xBC + (op) => { throw new NotImplementedException("0xBC"); - } }, - {0xBD, (op) => - { + }, + // 0xBD + (op) => { throw new NotImplementedException("0xBD"); - } }, - {0xBE, (op) => - { + }, + // 0xBE + (op) => { throw new NotImplementedException("0xBE"); - } }, - {0xBF, (op) => - { + }, + // 0xBF + (op) => { throw new NotImplementedException("0xBF"); - } }, + }, #endregion #region OpCodes 0xC0-0xCF - {0xC0, (op) => - { + // 0xC0 + (op) => { throw new NotImplementedException("0xC0"); - } }, - {0xC1, (op) => - { + }, + // 0xC1 + (op) => { throw new NotImplementedException("0xC1"); - } }, - {0xC2, (op) => - { + }, + // 0xC2 + (op) => { throw new NotImplementedException("0xC2"); - } }, - {0xC3, (op) => - { + }, + // 0xC3 + (op) => { throw new NotImplementedException("0xC3"); - } }, - {0xC4, (op) => - { + }, + // 0xC4 + (op) => { throw new NotImplementedException("0xC4"); - } }, - {0xC5, (op) => - { + }, + // 0xC5 + (op) => { throw new NotImplementedException("0xC5"); - } }, - {0xC6, (op) => - { + }, + // 0xC6 + (op) => { throw new NotImplementedException("0xC6"); - } }, - {0xC7, (op) => - { + }, + // 0xC7 + (op) => { throw new NotImplementedException("0xC7"); - } }, - {0xC8, (op) => - { + }, + // 0xC8 + (op) => { throw new NotImplementedException("0xC8"); - } }, - {0xC9, (op) => - { + }, + // 0xC9 + (op) => { throw new NotImplementedException("0xC9"); - } }, - {0xCA, (op) => - { + }, + // 0xCA + (op) => { throw new NotImplementedException("0xCA"); - } }, - {0xCB, (op) => - { + }, + // 0xCB + (op) => { throw new NotImplementedException("0xCB"); - } }, - {0xCC, (op) => - { + }, + // 0xCC + (op) => { throw new NotImplementedException("0xCC"); - } }, - {0xCD, (op) => - { + }, + // 0xCD + (op) => { throw new NotImplementedException("0xCD"); - } }, - {0xCE, (op) => - { + }, + // 0xCE + (op) => { throw new NotImplementedException("0xCE"); - } }, - {0xCF, (op) => - { + }, + // 0xCF + (op) => { throw new NotImplementedException("0xCF"); - } }, + }, #endregion #region OpCodes 0xD0-0xDF - {0xD0, (op) => - { + // 0xD0 + (op) => { throw new NotImplementedException("0xD0"); - } }, - {0xD1, (op) => - { + }, + // 0xD1 + (op) => { throw new NotImplementedException("0xD1"); - } }, - {0xD2, (op) => - { + }, + // 0xD2 + (op) => { throw new NotImplementedException("0xD2"); - } }, - {0xD3, (op) => - { + }, + // 0xD3 + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xD4, (op) => - { + }, + // 0xD4 + (op) => { throw new NotImplementedException("0xD4"); - } }, - {0xD5, (op) => - { + }, + // 0xD5 + (op) => { throw new NotImplementedException("0xD5"); - } }, - {0xD6, (op) => - { + }, + // 0xD6 + (op) => { throw new NotImplementedException("0xD6"); - } }, - {0xD7, (op) => - { + }, + // 0xD7 + (op) => { throw new NotImplementedException("0xD7"); - } }, - {0xD8, (op) => - { + }, + // 0xD8 + (op) => { throw new NotImplementedException("0xD8"); - } }, - {0xD9, (op) => - { + }, + // 0xD9 + (op) => { throw new NotImplementedException("0xD9"); - } }, - {0xDA, (op) => - { + }, + // 0xDA + (op) => { throw new NotImplementedException("0xDA"); - } }, - {0xDB, (op) => - { + }, + // 0xDB + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xDC, (op) => - { + }, + // 0xDC + (op) => { throw new NotImplementedException("0xDC"); - } }, - {0xDD, (op) => - { + }, + // 0xDD + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xDE, (op) => - { + }, + // 0xDE + (op) => { throw new NotImplementedException("0xDE"); - } }, - {0xDF, (op) => - { + }, + // 0xDF + (op) => { throw new NotImplementedException("0xDF"); - } }, + }, #endregion #region OpCodes 0xE0-0xEF - {0xE0, (op) => - { + // 0xE0 + (op) => { throw new NotImplementedException("0xE0"); - } }, - {0xE1, (op) => - { + }, + // 0xE1 + (op) => { throw new NotImplementedException("0xE1"); - } }, - {0xE2, (op) => - { + }, + // 0xE2 + (op) => { throw new NotImplementedException("0xE2"); - } }, - {0xE3, (op) => - { + }, + // 0xE3 + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xE4, (op) => - { + }, + // 0xE4 + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xE5, (op) => - { + }, + // 0xE5 + (op) => { throw new NotImplementedException("0xE5"); - } }, - {0xE6, (op) => - { + }, + // 0xE6 + (op) => { throw new NotImplementedException("0xE6"); - } }, - {0xE7, (op) => - { + }, + // 0xE7 + (op) => { throw new NotImplementedException("0xE7"); - } }, - {0xE8, (op) => - { + }, + // 0xE8 + (op) => { throw new NotImplementedException("0xE8"); - } }, - {0xE9, (op) => - { + }, + // 0xE9 + (op) => { throw new NotImplementedException("0xE9"); - } }, - {0xEA, (op) => - { + }, + // 0xEA + (op) => { throw new NotImplementedException("0xEA"); - } }, - {0xEB, (op) => - { + }, + // 0xEB + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xEC, (op) => - { + }, + // 0xEC + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xED, (op) => - { + }, + // 0xED + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xEE, (op) => - { + }, + // 0xEE + (op) => { throw new NotImplementedException("0xEE"); - } }, - {0xEF, (op) => - { + }, + // 0xEF + (op) => { throw new NotImplementedException("0xEF"); - } }, + }, #endregion #region OpCodes 0xF0-0xFF - {0xF0, (op) => - { + // 0xF0 + (op) => { throw new NotImplementedException("0xF0"); - } }, - {0xF1, (op) => - { + }, + // 0xF1 + (op) => { throw new NotImplementedException("0xF1"); - } }, - {0xF2, (op) => - { + }, + // 0xF2 + (op) => { throw new NotImplementedException("0xF2"); - } }, - {0xF3, (op) => - { + }, + // 0xF3 + (op) => { throw new NotImplementedException("0xF3"); - } }, - {0xF4, (op) => - { + }, + // 0xF4 + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xF5, (op) => - { + }, + // 0xF5 + (op) => { throw new NotImplementedException("0xF5"); - } }, - {0xF6, (op) => - { + }, + // 0xF6 + (op) => { throw new NotImplementedException("0xF6"); - } }, - {0xF7, (op) => - { + }, + // 0xF7 + (op) => { throw new NotImplementedException("0xF7"); - } }, - {0xF8, (op) => - { + }, + // 0xF8 + (op) => { throw new NotImplementedException("0xF8"); - } }, - {0xF9, (op) => - { + }, + // 0xF9 + (op) => { throw new NotImplementedException("0xF9"); - } }, - {0xFA, (op) => - { + }, + // 0xFA + (op) => { throw new NotImplementedException("0xFA"); - } }, - {0xFB, (op) => - { + }, + // 0xFB + (op) => { throw new NotImplementedException("0xFB"); - } }, - {0xFC, (op) => - { + }, + // 0xFC + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xFD, (op) => - { + }, + // 0xFD + (op) => { throw new IllegalInstructionException(op, "Instruction does not exist"); - } }, - {0xFE, (op) => - { + }, + // 0xFE + (op) => { throw new NotImplementedException("0xFE"); - } }, - {0xFF, (op) => - { + }, + // 0xFF + (op) => { throw new NotImplementedException("0xFF"); - } }, + } #endregion #endregion }; + } - // Arrays are faster than dictionaries? - // TODO: Test speed of dictionary vs array - OpCodeArray = OpCodeTable.OrderBy(o => o.Key).Select(o => o.Value).ToArray(); + 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); } }