diff --git a/MCEmuCore.GBMonolith/Cpu.cs b/MCEmuCore.GBMonolith/Cpu.cs index dd0b75a..c047812 100644 --- a/MCEmuCore.GBMonolith/Cpu.cs +++ b/MCEmuCore.GBMonolith/Cpu.cs @@ -14,6 +14,9 @@ namespace MCEmuCore.GBMonolith class Cpu { private readonly CpuRegisters registers; + private bool halted = false; + private bool interruptsEnabled = true; + private IMemory memory; #region OpCodes private readonly List> OpCodeArray; @@ -30,32 +33,23 @@ namespace MCEmuCore.GBMonolith // 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"); - } + registers.BC = ReadShortFromInstruction(); + return 12; }, // 0x02 (op) => { // LD (BC), A - throw new NotImplementedException("LD (BC), A"); + memory.WriteByte(0xFF00 + registers.BC, registers.A); + return 8; }, // 0x03 (op) => { registers.BC += 1; - registers.PC += 1; return 8; }, // 0x04 @@ -75,34 +69,27 @@ namespace MCEmuCore.GBMonolith // 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"); - } + registers.B = ReadInstruction(); + return 8; }, // 0x07 (op) => { // RLCA registers.Flags.Zero = false; - registers.Flags.Subtract = false; + registers.Flags.N_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"); + int address = ReadShortFromInstruction(); + memory.WriteShort(address, registers.SP); + return 20; }, // 0x09 (op) => { @@ -115,13 +102,13 @@ namespace MCEmuCore.GBMonolith (op) => { // LD A, (BC) // Load byte at address stored in BC into A - throw new NotImplementedException("LD A, (BC)"); + registers.A = memory.ReadByte(0xFF + registers.BC); + return 8; }, // 0x0B (op) => { // DEC BC registers.BC -= 1; - registers.PC += 1; return 8; }, // 0x0C @@ -141,27 +128,19 @@ namespace MCEmuCore.GBMonolith // 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"); - } + registers.C = ReadInstruction(); + return 8; }, // 0x0F (op) => { // RRCA registers.Flags.Zero = false; - registers.Flags.Subtract = false; + registers.Flags.N_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 @@ -175,27 +154,19 @@ namespace MCEmuCore.GBMonolith // 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"); - } + registers.DE = ReadShortFromInstruction(); + return 12; }, // 0x12 (op) => { // LD (DE), A - throw new NotImplementedException("0x12"); + memory.WriteByte(0xFF00 + registers.DE, registers.A); + return 8; }, // 0x13 (op) => { // INC DE registers.DE += 1; - registers.PC += 1; return 8; }, // 0x14 @@ -212,16 +183,8 @@ namespace MCEmuCore.GBMonolith }, // 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"); - } + registers.D = ReadInstruction(); + return 8; }, // 0x17 (op) => { @@ -229,26 +192,18 @@ namespace MCEmuCore.GBMonolith int carryBit = registers.Flags.Carry ? 1 : 0; registers.Flags.Zero = false; - registers.Flags.Subtract = false; + registers.Flags.N_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"); - } + byte jump = ReadInstruction(); + registers.PC += jump; + return 12; }, // 0x19 (op) => { @@ -261,13 +216,14 @@ namespace MCEmuCore.GBMonolith (op) => { // LD A, (DE) // Load byte at address stored in DE into A - throw new NotImplementedException("LD A, (DE)"); + byte val = memory.ReadByte(registers.DE); + registers.A = val; + return 8; }, // 0x1B (op) => { // DEC DE registers.DE -= 1; - registers.PC += 1; return 8; }, @@ -285,16 +241,8 @@ namespace MCEmuCore.GBMonolith }, // 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"); - } + registers.E = ReadInstruction(); + return 8; }, // 0x1F (op) => { @@ -302,43 +250,61 @@ namespace MCEmuCore.GBMonolith int carryBit = registers.Flags.Carry ? 1 : 0; registers.Flags.Zero = false; - registers.Flags.Subtract = false; + registers.Flags.N_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"); + byte relativeJump = ReadInstruction(); + if (!registers.Flags.Zero) + { + registers.PC += relativeJump; + return 12; + } + else + { + return 8; + } }, // 0x21 (op) => { - throw new NotImplementedException("0x21"); + // LD HL, d16 + registers.HL = ReadShortFromInstruction(); + return 12; }, // 0x22 (op) => { - throw new NotImplementedException("0x22"); + // LD (HL+), A + memory.WriteByte(registers.HL++, registers.A); + return 8; }, // 0x23 (op) => { - throw new NotImplementedException("0x23"); + registers.HL += 1; + return 8; }, // 0x24 (op) => { - throw new NotImplementedException("0x24"); + registers.H = IncrementRegister(registers.H); + + return 4; }, // 0x25 (op) => { - throw new NotImplementedException("0x25"); + registers.H = DecrementRegister(registers.H); + + return 4; }, // 0x26 (op) => { - throw new NotImplementedException("0x26"); + registers.H = ReadInstruction(); + return 8; }, // 0x27 (op) => { @@ -346,675 +312,921 @@ namespace MCEmuCore.GBMonolith }, // 0x28 (op) => { - throw new NotImplementedException("0x28"); + byte relativeJump = ReadInstruction(); + if (registers.Flags.Zero) + { + registers.PC += relativeJump; + return 12; + } + else + { + return 8; + } }, // 0x29 (op) => { - throw new NotImplementedException("0x29"); + registers.HL = AddWideRegisters(registers.HL, registers.HL); + + return 8; }, // 0x2A (op) => { - throw new NotImplementedException("0x2A"); + byte val = memory.ReadByte(registers.HL++); + registers.A = val; + return 8; }, // 0x2B (op) => { - throw new NotImplementedException("0x2B"); + registers.HL -= 1; + return 8; }, // 0x2C (op) => { - throw new NotImplementedException("0x2C"); + registers.L = IncrementRegister(registers.L); + + return 4; }, // 0x2D (op) => { - throw new NotImplementedException("0x2D"); + registers.L = DecrementRegister(registers.L); + + return 4; }, // 0x2E (op) => { - throw new NotImplementedException("0x2E"); + registers.L = ReadInstruction(); + return 8; }, // 0x2F (op) => { - throw new NotImplementedException("0x2F"); + registers.A = (byte)~registers.A; + registers.Flags.HalfCarry = true; + registers.Flags.N_Subtract = true; + return 4; }, #endregion #region OpCodes 0x30-0x3F // 0x30 (op) => { - throw new NotImplementedException("0x30"); + byte relativeJump = ReadInstruction(); + if (!registers.Flags.Carry) + { + registers.PC += relativeJump; + return 12; + } + else + { + return 8; + } }, // 0x31 (op) => { - throw new NotImplementedException("0x31"); + // LD SP, d16 + registers.SP = ReadShortFromInstruction(); + return 12; }, // 0x32 (op) => { - throw new NotImplementedException("0x32"); + memory.WriteByte(registers.HL--, registers.A); + return 8; }, // 0x33 (op) => { - throw new NotImplementedException("0x33"); + registers.SP += 1; + return 8; }, // 0x34 (op) => { - throw new NotImplementedException("0x34"); + byte val = IncrementRegister(memory.ReadByte(registers.HL)); + memory.WriteByte(registers.HL, val); + return 12; }, // 0x35 (op) => { - throw new NotImplementedException("0x35"); + byte val = DecrementRegister(memory.ReadByte(registers.HL)); + memory.WriteByte(registers.HL, val); + return 12; }, // 0x36 (op) => { - throw new NotImplementedException("0x36"); + byte val = ReadInstruction(); + memory.WriteByte(registers.HL, val); + return 12; }, // 0x37 (op) => { - throw new NotImplementedException("0x37"); + registers.Flags.Carry = true; + registers.Flags.HalfCarry = false; + registers.Flags.N_Subtract = false; + return 4; }, // 0x38 (op) => { - throw new NotImplementedException("0x38"); + byte relativeJump = ReadInstruction(); + if (registers.Flags.Carry) + { + registers.PC += relativeJump; + return 12; + } + else + { + return 8; + } }, // 0x39 (op) => { - throw new NotImplementedException("0x39"); + registers.HL = AddWideRegisters(registers.HL, registers.SP); + + return 8; }, // 0x3A (op) => { - throw new NotImplementedException("0x3A"); + registers.A = memory.ReadByte(registers.HL--); + return 8; }, // 0x3B (op) => { - throw new NotImplementedException("0x3B"); + registers.SP -= 1; + + return 8; }, // 0x3C (op) => { - throw new NotImplementedException("0x3C"); + registers.A = IncrementRegister(registers.A); + + return 4; }, // 0x3D (op) => { - throw new NotImplementedException("0x3D"); + registers.A = DecrementRegister(registers.A); + + return 4; }, // 0x3E (op) => { - throw new NotImplementedException("0x3E"); + registers.A = ReadInstruction(); + return 8; }, // 0x3F (op) => { - throw new NotImplementedException("0x3F"); + registers.Flags.Carry = !registers.Flags.Carry; + registers.Flags.HalfCarry = false; + registers.Flags.N_Subtract = false; + return 4; }, #endregion #region OpCodes 0x40-0x4F // 0x40 (op) => { - throw new NotImplementedException("0x40"); + registers.B = registers.B; + return 4; }, // 0x41 (op) => { - throw new NotImplementedException("0x41"); + registers.B = registers.C; + return 4; }, // 0x42 (op) => { - throw new NotImplementedException("0x42"); + registers.B = registers.D; + return 4; }, // 0x43 (op) => { - throw new NotImplementedException("0x43"); + registers.B = registers.E; + return 4; }, // 0x44 (op) => { - throw new NotImplementedException("0x44"); + registers.B = registers.H; + return 4; }, // 0x45 (op) => { - throw new NotImplementedException("0x45"); + registers.B = registers.L; + return 4; }, // 0x46 (op) => { - throw new NotImplementedException("0x46"); + registers.B = memory.ReadByte(registers.HL); + return 8; }, // 0x47 (op) => { - throw new NotImplementedException("0x47"); + registers.B = registers.A; + return 4; }, // 0x48 (op) => { - throw new NotImplementedException("0x48"); + registers.C = registers.B; + return 4; }, // 0x49 (op) => { - throw new NotImplementedException("0x49"); + registers.C = registers.C; + return 4; }, // 0x4A (op) => { - throw new NotImplementedException("0x4A"); + registers.C = registers.D; + return 4; }, // 0x4B (op) => { - throw new NotImplementedException("0x4B"); + registers.C = registers.E; + return 4; }, // 0x4C (op) => { - throw new NotImplementedException("0x4C"); + registers.C = registers.H; + return 4; }, // 0x4D (op) => { - throw new NotImplementedException("0x4D"); + registers.C = registers.L; + return 4; }, // 0x4E (op) => { - throw new NotImplementedException("0x4E"); + registers.C = memory.ReadByte(registers.HL); + return 8; }, // 0x4F (op) => { - throw new NotImplementedException("0x4F"); + registers.C = registers.A; + return 4; }, #endregion #region OpCodes 0x50-0x5F // 0x50 (op) => { - throw new NotImplementedException("0x50"); + registers.D = registers.B; + return 4; }, // 0x51 (op) => { - throw new NotImplementedException("0x51"); + registers.D = registers.C; + return 4; }, // 0x52 (op) => { - throw new NotImplementedException("0x52"); + registers.D = registers.D; + return 4; }, // 0x53 (op) => { - throw new NotImplementedException("0x53"); + registers.D = registers.E; + return 4; }, // 0x54 (op) => { - throw new NotImplementedException("0x54"); + registers.D = registers.H; + return 4; }, // 0x55 (op) => { - throw new NotImplementedException("0x55"); + registers.D = registers.L; + return 4; }, // 0x56 (op) => { - throw new NotImplementedException("0x56"); + registers.D = memory.ReadByte(registers.HL); + return 8; }, // 0x57 (op) => { - throw new NotImplementedException("0x57"); + registers.D = registers.A; + return 4; }, // 0x58 (op) => { - throw new NotImplementedException("0x58"); + registers.E = registers.B; + return 4; }, // 0x59 (op) => { - throw new NotImplementedException("0x59"); + registers.E = registers.C; + return 4; }, // 0x5A (op) => { - throw new NotImplementedException("0x5A"); + registers.E = registers.D; + return 4; }, // 0x5B (op) => { - throw new NotImplementedException("0x5B"); + registers.E = registers.E; + return 4; }, // 0x5C (op) => { - throw new NotImplementedException("0x5C"); + registers.E = registers.H; + return 4; }, // 0x5D (op) => { - throw new NotImplementedException("0x5D"); + registers.E = registers.L; + return 4; }, // 0x5E (op) => { - throw new NotImplementedException("0x5E"); + registers.E = memory.ReadByte(registers.HL); + return 8; }, // 0x5F (op) => { - throw new NotImplementedException("0x5F"); + registers.E = registers.A; + return 4; }, #endregion #region OpCodes 0x60-0x6F // 0x60 (op) => { - throw new NotImplementedException("0x60"); + registers.H = registers.B; + return 4; }, // 0x61 (op) => { - throw new NotImplementedException("0x61"); + registers.H = registers.C; + return 4; }, // 0x62 (op) => { - throw new NotImplementedException("0x62"); + registers.H = registers.D; + return 4; }, // 0x63 (op) => { - throw new NotImplementedException("0x63"); + registers.H = registers.E; + return 4; }, // 0x64 (op) => { - throw new NotImplementedException("0x64"); + registers.H = registers.H; + return 4; }, // 0x65 (op) => { - throw new NotImplementedException("0x65"); + registers.H = registers.L; + return 4; }, // 0x66 (op) => { - throw new NotImplementedException("0x66"); + registers.H = memory.ReadByte(registers.HL); + return 8; }, // 0x67 (op) => { - throw new NotImplementedException("0x67"); + registers.H = registers.A; + return 4; }, // 0x68 (op) => { - throw new NotImplementedException("0x68"); + registers.L = registers.B; + return 4; }, // 0x69 (op) => { - throw new NotImplementedException("0x69"); + registers.L = registers.C; + return 4; }, // 0x6A (op) => { - throw new NotImplementedException("0x6A"); + registers.L = registers.D; + return 4; }, // 0x6B (op) => { - throw new NotImplementedException("0x6B"); + registers.L = registers.E; + return 4; }, // 0x6C (op) => { - throw new NotImplementedException("0x6C"); + registers.L = registers.H; + return 4; }, // 0x6D (op) => { - throw new NotImplementedException("0x6D"); + registers.L = registers.L; + return 4; }, // 0x6E (op) => { - throw new NotImplementedException("0x6E"); + registers.L = memory.ReadByte(registers.HL); + return 8; }, // 0x6F (op) => { - throw new NotImplementedException("0x6F"); + registers.L = registers.A; + return 4; }, #endregion #region OpCodes 0x70-0x7F // 0x70 (op) => { - throw new NotImplementedException("0x70"); + memory.WriteByte(registers.HL, registers.B); + return 8; }, // 0x71 (op) => { - throw new NotImplementedException("0x71"); + memory.WriteByte(registers.HL, registers.C); + return 8; }, // 0x72 (op) => { - throw new NotImplementedException("0x72"); + memory.WriteByte(registers.HL, registers.D); + return 8; }, // 0x73 (op) => { - throw new NotImplementedException("0x73"); + memory.WriteByte(registers.HL, registers.E); + return 8; }, // 0x74 (op) => { - throw new NotImplementedException("0x74"); + memory.WriteByte(registers.HL, registers.H); + return 8; }, // 0x75 (op) => { - throw new NotImplementedException("0x75"); + memory.WriteByte(registers.HL, registers.L); + return 8; }, // 0x76 (op) => { - throw new NotImplementedException("0x76"); + halted = true; + return 4; }, // 0x77 (op) => { - throw new NotImplementedException("0x77"); + memory.WriteByte(registers.HL, registers.A); + return 8; }, // 0x78 (op) => { - throw new NotImplementedException("0x78"); + registers.A = registers.B; + return 4; }, // 0x79 (op) => { - throw new NotImplementedException("0x79"); + registers.A = registers.C; + return 4; }, // 0x7A (op) => { - throw new NotImplementedException("0x7A"); + registers.A = registers.D; + return 4; }, // 0x7B (op) => { - throw new NotImplementedException("0x7B"); + registers.A = registers.E; + return 4; }, // 0x7C (op) => { - throw new NotImplementedException("0x7C"); + registers.A = registers.H; + return 4; }, // 0x7D (op) => { - throw new NotImplementedException("0x7D"); + registers.A = registers.L; + return 4; }, // 0x7E (op) => { - throw new NotImplementedException("0x7E"); + registers.A = memory.ReadByte(registers.HL); + return 8; }, // 0x7F (op) => { - throw new NotImplementedException("0x7F"); + registers.A = registers.A; + return 4; }, #endregion #region OpCodes 0x80-0x8F // 0x80 (op) => { - throw new NotImplementedException("0x80"); + registers.A = AddRegisters(registers.A, registers.B); + return 4; }, // 0x81 (op) => { - throw new NotImplementedException("0x81"); + registers.A = AddRegisters(registers.A, registers.C); + return 4; }, // 0x82 (op) => { - throw new NotImplementedException("0x82"); + registers.A = AddRegisters(registers.A, registers.D); + return 4; }, // 0x83 (op) => { - throw new NotImplementedException("0x83"); + registers.A = AddRegisters(registers.A, registers.E); + return 4; }, // 0x84 (op) => { - throw new NotImplementedException("0x84"); + registers.A = AddRegisters(registers.A, registers.H); + return 4; }, // 0x85 (op) => { - throw new NotImplementedException("0x85"); + registers.A = AddRegisters(registers.A, registers.L); + return 4; }, // 0x86 (op) => { - throw new NotImplementedException("0x86"); + registers.A = AddRegisters(registers.A, memory.ReadByte(registers.HL)); + return 8; }, // 0x87 (op) => { - throw new NotImplementedException("0x87"); + registers.A = AddRegisters(registers.A, registers.A); + return 4; }, // 0x88 (op) => { - throw new NotImplementedException("0x88"); + registers.A = AddRegisters(registers.A, registers.B, true); + return 4; }, // 0x89 (op) => { - throw new NotImplementedException("0x89"); + registers.A = AddRegisters(registers.A, registers.C, true); + return 4; }, // 0x8A (op) => { - throw new NotImplementedException("0x8A"); + registers.A = AddRegisters(registers.A, registers.D, true); + return 4; }, // 0x8B (op) => { - throw new NotImplementedException("0x8B"); + registers.A = AddRegisters(registers.A, registers.E, true); + return 4; }, // 0x8C (op) => { - throw new NotImplementedException("0x8C"); + registers.A = AddRegisters(registers.A, registers.H, true); + return 4; }, // 0x8D (op) => { - throw new NotImplementedException("0x8D"); + registers.A = AddRegisters(registers.A, registers.L, true); + return 4; }, // 0x8E (op) => { - throw new NotImplementedException("0x8E"); + registers.A = AddRegisters(registers.A, memory.ReadByte(registers.HL), true); + return 8; }, // 0x8F (op) => { - throw new NotImplementedException("0x8F"); + registers.A = AddRegisters(registers.A, registers.A, true); + return 4; }, #endregion #region OpCodes 0x90-0x9F // 0x90 (op) => { - throw new NotImplementedException("0x90"); + registers.A = SubtractRegisters(registers.A, registers.B); + return 4; }, // 0x91 (op) => { - throw new NotImplementedException("0x91"); + registers.A = SubtractRegisters(registers.A, registers.C); + return 4; }, // 0x92 (op) => { - throw new NotImplementedException("0x92"); + registers.A = SubtractRegisters(registers.A, registers.D); + return 4; }, // 0x93 (op) => { - throw new NotImplementedException("0x93"); + registers.A = SubtractRegisters(registers.A, registers.E); + return 4; }, // 0x94 (op) => { - throw new NotImplementedException("0x94"); + registers.A = SubtractRegisters(registers.A, registers.H); + return 4; }, // 0x95 (op) => { - throw new NotImplementedException("0x95"); + registers.A = SubtractRegisters(registers.A, registers.L); + return 4; }, // 0x96 (op) => { - throw new NotImplementedException("0x96"); + registers.A = SubtractRegisters(registers.A, memory.ReadByte(registers.HL)); + return 8; }, // 0x97 (op) => { - throw new NotImplementedException("0x97"); + registers.A = SubtractRegisters(registers.A, registers.A); + return 4; }, // 0x98 (op) => { - throw new NotImplementedException("0x98"); + registers.A = SubtractRegisters(registers.A, registers.B, true); + return 4; }, // 0x99 (op) => { - throw new NotImplementedException("0x99"); + registers.A = SubtractRegisters(registers.A, registers.C, true); + return 4; }, // 0x9A (op) => { - throw new NotImplementedException("0x9A"); + registers.A = SubtractRegisters(registers.A, registers.D, true); + return 4; }, // 0x9B (op) => { - throw new NotImplementedException("0x9B"); + registers.A = SubtractRegisters(registers.A, registers.E, true); + return 4; }, // 0x9C (op) => { - throw new NotImplementedException("0x9C"); + registers.A = SubtractRegisters(registers.A, registers.H, true); + return 4; }, // 0x9D (op) => { - throw new NotImplementedException("0x9D"); + registers.A = SubtractRegisters(registers.A, registers.L, true); + return 4; }, // 0x9E (op) => { - throw new NotImplementedException("0x9E"); + registers.A = SubtractRegisters(registers.A, memory.ReadByte(registers.HL), true); + return 8; }, // 0x9F (op) => { - throw new NotImplementedException("0x9F"); + registers.A = SubtractRegisters(registers.A, registers.A, true); + return 4; }, #endregion #region OpCodes 0xA0-0xAF // 0xA0 (op) => { - throw new NotImplementedException("0xA0"); + registers.A = (byte)(registers.A & registers.B); + return 4; }, // 0xA1 (op) => { - throw new NotImplementedException("0xA1"); + registers.A = (byte)(registers.A & registers.C); + return 4; }, // 0xA2 (op) => { - throw new NotImplementedException("0xA2"); + registers.A = (byte)(registers.A & registers.D); + return 4; }, // 0xA3 (op) => { - throw new NotImplementedException("0xA3"); + registers.A = (byte)(registers.A & registers.E); + return 4; }, // 0xA4 (op) => { - throw new NotImplementedException("0xA4"); + registers.A = (byte)(registers.A & registers.H); + return 4; }, // 0xA5 (op) => { - throw new NotImplementedException("0xA5"); + registers.A = (byte)(registers.A & registers.L); + return 4; }, // 0xA6 (op) => { - throw new NotImplementedException("0xA6"); + registers.A = (byte)(registers.A & memory.ReadByte(registers.HL)); + return 8; }, // 0xA7 (op) => { - throw new NotImplementedException("0xA7"); + registers.A = (byte)(registers.A & registers.A); + return 4; }, // 0xA8 (op) => { - throw new NotImplementedException("0xA8"); + registers.A = (byte)(registers.A ^ registers.B); + return 4; }, // 0xA9 (op) => { - throw new NotImplementedException("0xA9"); + registers.A = (byte)(registers.A ^ registers.C); + return 4; }, // 0xAA (op) => { - throw new NotImplementedException("0xAA"); + registers.A = (byte)(registers.A ^ registers.D); + return 4; }, // 0xAB (op) => { - throw new NotImplementedException("0xAB"); + registers.A = (byte)(registers.A ^ registers.E); + return 4; }, // 0xAC (op) => { - throw new NotImplementedException("0xAC"); + registers.A = (byte)(registers.A ^ registers.H); + return 4; }, // 0xAD (op) => { - throw new NotImplementedException("0xAD"); + registers.A = (byte)(registers.A ^ registers.L); + return 4; }, // 0xAE (op) => { - throw new NotImplementedException("0xAE"); + registers.A = (byte)(registers.A ^ memory.ReadByte(registers.HL)); + return 8; }, // 0xAF (op) => { - throw new NotImplementedException("0xAF"); + registers.A = (byte)(registers.A ^ registers.A); + return 4; }, #endregion #region OpCodes 0xB0-0xBF // 0xB0 (op) => { - throw new NotImplementedException("0xB0"); + registers.A = (byte)(registers.A | registers.B); + return 4; }, // 0xB1 (op) => { - throw new NotImplementedException("0xB1"); + registers.A = (byte)(registers.A | registers.C); + return 4; }, // 0xB2 (op) => { - throw new NotImplementedException("0xB2"); + registers.A = (byte)(registers.A | registers.D); + return 4; }, // 0xB3 (op) => { - throw new NotImplementedException("0xB3"); + registers.A = (byte)(registers.A | registers.E); + return 4; }, // 0xB4 (op) => { - throw new NotImplementedException("0xB4"); + registers.A = (byte)(registers.A | registers.H); + return 4; }, // 0xB5 (op) => { - throw new NotImplementedException("0xB5"); + registers.A = (byte)(registers.A | registers.L); + return 4; }, // 0xB6 (op) => { - throw new NotImplementedException("0xB6"); + registers.A = (byte)(registers.A | memory.ReadByte(registers.HL)); + return 8; }, // 0xB7 (op) => { - throw new NotImplementedException("0xB7"); + registers.A = (byte)(registers.A | registers.A); + return 4; }, // 0xB8 (op) => { - throw new NotImplementedException("0xB8"); + SubtractRegisters(registers.A, registers.B); + return 4; }, // 0xB9 (op) => { - throw new NotImplementedException("0xB9"); + SubtractRegisters(registers.A, registers.C); + return 4; }, // 0xBA (op) => { - throw new NotImplementedException("0xBA"); + SubtractRegisters(registers.A, registers.D); + return 4; }, // 0xBB (op) => { - throw new NotImplementedException("0xBB"); + SubtractRegisters(registers.A, registers.E); + return 4; }, // 0xBC (op) => { - throw new NotImplementedException("0xBC"); + SubtractRegisters(registers.A, registers.H); + return 4; }, // 0xBD (op) => { - throw new NotImplementedException("0xBD"); + SubtractRegisters(registers.A, registers.L); + return 4; }, // 0xBE (op) => { - throw new NotImplementedException("0xBE"); + SubtractRegisters(registers.A, memory.ReadByte(registers.HL)); + return 8; }, // 0xBF (op) => { - throw new NotImplementedException("0xBF"); + SubtractRegisters(registers.A, registers.A); + return 4; }, #endregion #region OpCodes 0xC0-0xCF // 0xC0 (op) => { - throw new NotImplementedException("0xC0"); + if (!registers.Flags.Zero) + { + Jump(PopShort()); + return 20; + } + else + { + return 8; + } }, // 0xC1 (op) => { - throw new NotImplementedException("0xC1"); + registers.BC = PopShort(); + return 12; }, // 0xC2 (op) => { - throw new NotImplementedException("0xC2"); + ushort jumpAddress = ReadShortFromInstruction(); + if (!registers.Flags.Zero) + { + Jump(jumpAddress); + return 16; + } + else + { + return 12; + } }, // 0xC3 (op) => { - throw new NotImplementedException("0xC3"); + ushort jumpAddress = ReadShortFromInstruction(); + Jump(jumpAddress); + return 16; }, // 0xC4 (op) => { - throw new NotImplementedException("0xC4"); + ushort jumpAddress = ReadShortFromInstruction(); + if (!registers.Flags.Zero) + { + PushShort(registers.PC); + Jump(jumpAddress); + return 16; + } + else + { + return 12; + } }, // 0xC5 (op) => { - throw new NotImplementedException("0xC5"); + PushShort(registers.BC); + return 16; }, // 0xC6 (op) => { - throw new NotImplementedException("0xC6"); + registers.A = AddRegisters(registers.A, ReadInstruction()); + return 8; }, // 0xC7 (op) => { - throw new NotImplementedException("0xC7"); + PushShort(registers.PC); + Jump(0x0000); + return 16; }, // 0xC8 (op) => { - throw new NotImplementedException("0xC8"); + if (registers.Flags.Zero) + { + Jump(PopShort()); + return 20; + } + else + { + return 8; + } }, // 0xC9 (op) => { - throw new NotImplementedException("0xC9"); + Jump(PopShort()); + return 16; }, // 0xCA (op) => { - throw new NotImplementedException("0xCA"); + ushort jumpAddress = ReadShortFromInstruction(); + if (registers.Flags.Zero) + { + Jump(jumpAddress); + return 16; + } + else + { + return 12; + } }, // 0xCB (op) => { @@ -1022,19 +1234,34 @@ namespace MCEmuCore.GBMonolith }, // 0xCC (op) => { - throw new NotImplementedException("0xCC"); + ushort jumpAddress = ReadShortFromInstruction(); + if (registers.Flags.Zero) + { + PushShort(registers.PC); + Jump(jumpAddress); + return 24; + } + else + { + return 12; + } }, // 0xCD (op) => { - throw new NotImplementedException("0xCD"); + PushShort(registers.PC); + Jump(ReadShortFromInstruction()); + return 24; }, // 0xCE (op) => { - throw new NotImplementedException("0xCE"); + registers.A = AddRegisters(registers.A, ReadInstruction(), true); + return 8; }, // 0xCF (op) => { - throw new NotImplementedException("0xCF"); + PushShort(registers.PC); + Jump(0x0008); + return 16; }, #endregion #region OpCodes 0xD0-0xDF @@ -1239,41 +1466,96 @@ namespace MCEmuCore.GBMonolith }; } + private void Jump(ushort address) + { + registers.PC = address; + } + + private void Jump(byte msb, byte lsb) + { + Jump(BytesToShort(msb, lsb)); + } + + private void PushShort(ushort value) + { + memory.WriteByte(--registers.SP, (byte)(value >> 8)); + memory.WriteByte(--registers.SP, (byte)(value & 0xFF)); + } + + private ushort PopShort() + { + byte lsb = memory.ReadByte(registers.SP++); + byte msb = memory.ReadByte(registers.SP++); + return BytesToShort(msb, lsb); + } + + private byte ReadInstruction() + { + registers.PC += 1; + return 0; + } + + private ushort ReadShortFromInstruction() + { + byte lsb = ReadInstruction(); + byte msb = ReadInstruction(); + return BytesToShort(msb, lsb); + } + + private ushort BytesToShort(byte msb, byte lsb) + { + return (ushort)(lsb + (msb << 8)); + } + 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; + return AddRegisters(register, 1); } private byte DecrementRegister(byte register) { - byte reg = (byte)((uint)register - 1); + return SubtractRegisters(register, 1); + } - registers.Flags.Subtract = true; + private byte AddRegisters(byte register1, byte register2, bool withCarry = false) + { + if (withCarry && registers.Flags.Carry) + { + register2 += 1; + } + byte reg = (byte)(register1 + register2); + + registers.Flags.N_Subtract = false; registers.Flags.Zero = reg == 0; - // This logic only works for the decrement operation - registers.Flags.HalfCarry = reg == 15; + registers.Flags.Carry = ((register1 + register2) & 0x100) == 0x100; + registers.Flags.HalfCarry = (((register1 & 0xf) + (register2 & 0xf)) & 0x10) == 0x10; + + return reg; + } + + private byte SubtractRegisters(byte register1, byte register2, bool withCarry = false) + { + if (withCarry && registers.Flags.Carry) + { + register2 += 1; + } + byte reg = (byte)(register1 - register2); + + registers.Flags.N_Subtract = true; + registers.Flags.Zero = reg == 0; + registers.Flags.Carry = ((0x100 + register1 + register2) & 0x100) == 0x100; + registers.Flags.HalfCarry = ((0x10 + (register1 & 0xf) - (register2 & 0xf)) & 0x10) == 0x10; - registers.PC += 1; return reg; } private ushort AddWideRegisters(ushort wideRegister1, ushort wideRegister2) { // ADD HL, BC - registers.Flags.Subtract = false; + registers.Flags.N_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); } } diff --git a/MCEmuCore.GBMonolith/CpuRegisters.cs b/MCEmuCore.GBMonolith/CpuRegisters.cs index 4aeced5..ecbbb43 100644 --- a/MCEmuCore.GBMonolith/CpuRegisters.cs +++ b/MCEmuCore.GBMonolith/CpuRegisters.cs @@ -241,7 +241,7 @@ namespace MCEmuCore.GBMonolith { Console.WriteLine("Flag status:"); Console.WriteLine($"Zero:\t\t{Flags.Zero}"); - Console.WriteLine($"Subtract:\t{Flags.Subtract}"); + Console.WriteLine($"Subtract:\t{Flags.N_Subtract}"); Console.WriteLine($"Half Carry:\t{Flags.HalfCarry}"); Console.WriteLine($"Carry:\t\t{Flags.Carry}"); Console.WriteLine($"Raw Register:\t{Convert.ToString(Flags.Value, 2)}"); @@ -269,7 +269,7 @@ namespace MCEmuCore.GBMonolith register &= 0b0111_0000; } } - public bool Subtract + public bool N_Subtract { get { return (Value & 0b0100_0000) != 0; } set diff --git a/MCEmuCore.GBMonolith/IMemory.cs b/MCEmuCore.GBMonolith/IMemory.cs new file mode 100644 index 0000000..924558d --- /dev/null +++ b/MCEmuCore.GBMonolith/IMemory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MCEmuCore.GBMonolith +{ + interface IMemory + { + byte ReadByte(int address); + ushort ReadShort(int address); + bool WriteByte(int address, byte value); + bool WriteShort(int address, ushort value); + } +} diff --git a/MCEmuCore.GBMonolith/Program.cs b/MCEmuCore.GBMonolith/Program.cs index 24f7ee6..4d42a40 100644 --- a/MCEmuCore.GBMonolith/Program.cs +++ b/MCEmuCore.GBMonolith/Program.cs @@ -51,7 +51,7 @@ namespace MCEmuCore.GBMonolith Console.WriteLine("Testing Flags:"); cpuRegisters.PrintFlags(); cpuRegisters.Flags.Zero = true; - cpuRegisters.Flags.Subtract = true; + cpuRegisters.Flags.N_Subtract = true; cpuRegisters.Flags.HalfCarry = true; cpuRegisters.Flags.Carry = false; cpuRegisters.PrintFlags();