From e2690d3132647021b76a9184ac561a78bede75ac Mon Sep 17 00:00:00 2001 From: ear7h Date: Fri, 23 Nov 2018 15:07:52 -0800 Subject: [PATCH 1/3] changed instruction switch satatement into a function table, some minor changes to the cb_table function which unecessarily converted indexes to bytes --- pkg/gb/gameboy.go | 6 +- pkg/gb/instructions.go | 1186 +--------------------------- pkg/gb/instructions_cb.go | 73 +- pkg/gb/instructions_table.go | 1443 ++++++++++++++++++++++++++++++++++ 4 files changed, 1486 insertions(+), 1222 deletions(-) create mode 100644 pkg/gb/instructions_table.go diff --git a/pkg/gb/gameboy.go b/pkg/gb/gameboy.go index 286c804..f59139c 100644 --- a/pkg/gb/gameboy.go +++ b/pkg/gb/gameboy.go @@ -50,9 +50,11 @@ type Gameboy struct { interruptsOn bool halted bool - cbInst []func() + cbInst [0x100]func() InputMask byte + mainInst [0x100]func() + // Flag if the game is running in cgb mode. For this to be true the game // rom must support cgb mode and the option be true. cgbMode bool @@ -320,6 +322,8 @@ func (gb *Gameboy) setup() error { gb.cbInst = gb.cbInstructions() + gb.mainInst = gb.mainInstructions() + gb.SpritePalette = NewPalette() gb.BGPalette = NewPalette() diff --git a/pkg/gb/instructions.go b/pkg/gb/instructions.go index b2d00c2..21c1a52 100644 --- a/pkg/gb/instructions.go +++ b/pkg/gb/instructions.go @@ -1,9 +1,5 @@ package gb -import ( - "log" -) - // OpcodeCycles is the number of cpu cycles for each normal opcode. var OpcodeCycles = []int{ 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 @@ -69,1185 +65,5 @@ func (gb *Gameboy) popPC16() uint16 { // ExecuteOpcode is a large switch statement containing the opcode operations. func (gb *Gameboy) ExecuteOpcode(opcode byte) { - switch opcode { - // LD B, n - case 0x06: - gb.CPU.BC.SetHi(gb.popPC()) - - // LD C, n - case 0x0E: - gb.CPU.BC.SetLo(gb.popPC()) - - // LD D, n - case 0x16: - gb.CPU.DE.SetHi(gb.popPC()) - - // LD E, n - case 0x1E: - gb.CPU.DE.SetLo(gb.popPC()) - - // LD H, n - case 0x26: - gb.CPU.HL.SetHi(gb.popPC()) - - // LD L, n - case 0x2E: - gb.CPU.HL.SetLo(gb.popPC()) - - // LD A,A - case 0x7F: - gb.CPU.AF.SetHi(gb.CPU.AF.Hi()) - - // LD A,B - case 0x78: - gb.CPU.AF.SetHi(gb.CPU.BC.Hi()) - - // LD A,C - case 0x79: - gb.CPU.AF.SetHi(gb.CPU.BC.Lo()) - - // LD A,D - case 0x7A: - gb.CPU.AF.SetHi(gb.CPU.DE.Hi()) - - // LD A,E - case 0x7B: - gb.CPU.AF.SetHi(gb.CPU.DE.Lo()) - - // LD A,H - case 0x7C: - gb.CPU.AF.SetHi(gb.CPU.HL.Hi()) - - // LD A,L - case 0x7D: - gb.CPU.AF.SetHi(gb.CPU.HL.Lo()) - - // LD A,(BC) - case 0x0A: - val := gb.Memory.Read(gb.CPU.BC.HiLo()) - gb.CPU.AF.SetHi(val) - - // LD A,(DE) - case 0x1A: - val := gb.Memory.Read(gb.CPU.DE.HiLo()) - gb.CPU.AF.SetHi(val) - - // LD A,(HL) - case 0x7E: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - - // LD A,(nn) - case 0xFA: - val := gb.Memory.Read(gb.popPC16()) - gb.CPU.AF.SetHi(val) - - // LD A,(nn) - case 0x3E: - val := gb.popPC() - gb.CPU.AF.SetHi(val) - - // LD B,A - case 0x47: - gb.CPU.BC.SetHi(gb.CPU.AF.Hi()) - - // LD B,B - case 0x40: - gb.CPU.BC.SetHi(gb.CPU.BC.Hi()) - - // LD B,C - case 0x41: - gb.CPU.BC.SetHi(gb.CPU.BC.Lo()) - - // LD B,D - case 0x42: - gb.CPU.BC.SetHi(gb.CPU.DE.Hi()) - - // LD B,E - case 0x43: - gb.CPU.BC.SetHi(gb.CPU.DE.Lo()) - - // LD B,H - case 0x44: - gb.CPU.BC.SetHi(gb.CPU.HL.Hi()) - - // LD B,L - case 0x45: - gb.CPU.BC.SetHi(gb.CPU.HL.Lo()) - - // LD B,(HL) - case 0x46: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.BC.SetHi(val) - - // LD C,A - case 0x4F: - gb.CPU.BC.SetLo(gb.CPU.AF.Hi()) - - // LD C,B - case 0x48: - gb.CPU.BC.SetLo(gb.CPU.BC.Hi()) - - // LD C,C - case 0x49: - gb.CPU.BC.SetLo(gb.CPU.BC.Lo()) - - // LD C,D - case 0x4A: - gb.CPU.BC.SetLo(gb.CPU.DE.Hi()) - - // LD C,E - case 0x4B: - gb.CPU.BC.SetLo(gb.CPU.DE.Lo()) - - // LD C,H - case 0x4C: - gb.CPU.BC.SetLo(gb.CPU.HL.Hi()) - - // LD C,L - case 0x4D: - gb.CPU.BC.SetLo(gb.CPU.HL.Lo()) - - // LD C,(HL) - case 0x4E: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.BC.SetLo(val) - - // LD D,A - case 0x57: - gb.CPU.DE.SetHi(gb.CPU.AF.Hi()) - - // LD D,B - case 0x50: - gb.CPU.DE.SetHi(gb.CPU.BC.Hi()) - - // LD D,C - case 0x51: - gb.CPU.DE.SetHi(gb.CPU.BC.Lo()) - - // LD D,D - case 0x52: - gb.CPU.DE.SetHi(gb.CPU.DE.Hi()) - - // LD D,E - case 0x53: - gb.CPU.DE.SetHi(gb.CPU.DE.Lo()) - - // LD D,H - case 0x54: - gb.CPU.DE.SetHi(gb.CPU.HL.Hi()) - - // LD D,L - case 0x55: - gb.CPU.DE.SetHi(gb.CPU.HL.Lo()) - - // LD D,(HL) - case 0x56: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.DE.SetHi(val) - - // LD E,A - case 0x5F: - gb.CPU.DE.SetLo(gb.CPU.AF.Hi()) - - // LD E,B - case 0x58: - gb.CPU.DE.SetLo(gb.CPU.BC.Hi()) - - // LD E,C - case 0x59: - gb.CPU.DE.SetLo(gb.CPU.BC.Lo()) - - // LD E,D - case 0x5A: - gb.CPU.DE.SetLo(gb.CPU.DE.Hi()) - - // LD E,E - case 0x5B: - gb.CPU.DE.SetLo(gb.CPU.DE.Lo()) - - // LD E,H - case 0x5C: - gb.CPU.DE.SetLo(gb.CPU.HL.Hi()) - - // LD E,L - case 0x5D: - gb.CPU.DE.SetLo(gb.CPU.HL.Lo()) - - // LD E,(HL) - case 0x5E: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.DE.SetLo(val) - - // LD H,A - case 0x67: - gb.CPU.HL.SetHi(gb.CPU.AF.Hi()) - - // LD H,B - case 0x60: - gb.CPU.HL.SetHi(gb.CPU.BC.Hi()) - - // LD H,C - case 0x61: - gb.CPU.HL.SetHi(gb.CPU.BC.Lo()) - - // LD H,D - case 0x62: - gb.CPU.HL.SetHi(gb.CPU.DE.Hi()) - - // LD H,E - case 0x63: - gb.CPU.HL.SetHi(gb.CPU.DE.Lo()) - - // LD H,H - case 0x64: - gb.CPU.HL.SetHi(gb.CPU.HL.Hi()) - - // LD H,L - case 0x65: - gb.CPU.HL.SetHi(gb.CPU.HL.Lo()) - - // LD H,(HL) - case 0x66: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.HL.SetHi(val) - - // LD L,A - case 0x6F: - gb.CPU.HL.SetLo(gb.CPU.AF.Hi()) - - // LD L,B - case 0x68: - gb.CPU.HL.SetLo(gb.CPU.BC.Hi()) - - // LD L,C - case 0x69: - gb.CPU.HL.SetLo(gb.CPU.BC.Lo()) - - // LD L,D - case 0x6A: - gb.CPU.HL.SetLo(gb.CPU.DE.Hi()) - - // LD L,E - case 0x6B: - gb.CPU.HL.SetLo(gb.CPU.DE.Lo()) - - // LD L,H - case 0x6C: - gb.CPU.HL.SetLo(gb.CPU.HL.Hi()) - - // LD L,L - case 0x6D: - gb.CPU.HL.SetLo(gb.CPU.HL.Lo()) - - // LD L,(HL) - case 0x6E: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.HL.SetLo(val) - - // LD (HL),A - case 0x77: - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),B - case 0x70: - val := gb.CPU.BC.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),C - case 0x71: - val := gb.CPU.BC.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),D - case 0x72: - val := gb.CPU.DE.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),E - case 0x73: - val := gb.CPU.DE.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),H - case 0x74: - val := gb.CPU.HL.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),L - case 0x75: - val := gb.CPU.HL.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (HL),n 36 - case 0x36: - val := gb.popPC() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - // LD (BC),A - case 0x02: - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.BC.HiLo(), val) - - // LD (DE),A - case 0x12: - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.DE.HiLo(), val) - - // LD (nn),A - case 0xEA: - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.popPC16(), val) - - // LD A,(C) - case 0xF2: - val := 0xFF00 + uint16(gb.CPU.BC.Lo()) - gb.CPU.AF.SetHi(gb.Memory.Read(val)) - - // LD (C),A - case 0xE2: - val := gb.CPU.AF.Hi() - mem := 0xFF00 + uint16(gb.CPU.BC.Lo()) - gb.Memory.Write(mem, val) - - // LDD A,(HL) - case 0x3A: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) - - // LDD (HL),A - case 0x32: - val := gb.CPU.HL.HiLo() - gb.Memory.Write(val, gb.CPU.AF.Hi()) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) - - // LDI A,(HL) - case 0x2A: - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) - - // LDI (HL),A - case 0x22: - val := gb.CPU.HL.HiLo() - gb.Memory.Write(val, gb.CPU.AF.Hi()) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) - - // LD (0xFF00+n),A - case 0xE0: - val := 0xFF00 + uint16(gb.popPC()) - gb.Memory.Write(val, gb.CPU.AF.Hi()) - - // LD A,(0xFF00+n) - case 0xF0: - val := gb.Memory.ReadHighRam(0xFF00 + uint16(gb.popPC())) - gb.CPU.AF.SetHi(val) - - // ========== 16-Bit Loads =========== - - // LD BC,nn - case 0x01: - val := gb.popPC16() - gb.CPU.BC.Set(val) - - // LD DE,nn - case 0x11: - val := gb.popPC16() - gb.CPU.DE.Set(val) - - // LD HL,nn - case 0x21: - val := gb.popPC16() - gb.CPU.HL.Set(val) - - // LD SP,nn - case 0x31: - val := gb.popPC16() - gb.CPU.SP.Set(val) - - // LD SP,HL - case 0xF9: - val := gb.CPU.HL - gb.CPU.SP = val - - // LD HL,SP+n - case 0xF8: - val1 := int32(gb.CPU.SP.HiLo()) - val2 := int32(int8(gb.popPC())) - result := val1 + val2 - gb.CPU.HL.Set(uint16(result)) - tempVal := val1 ^ val2 ^ result - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - // TODO: Probably check these - gb.CPU.SetH((tempVal & 0x10) == 0x10) - gb.CPU.SetC((tempVal & 0x100) == 0x100) - - // LD (nn),SP - case 0x08: - address := gb.popPC16() - gb.Memory.Write(address, gb.CPU.SP.Lo()) - gb.Memory.Write(address+1, gb.CPU.SP.Hi()) - - // PUSH AF - case 0xF5: - gb.pushStack(gb.CPU.AF.HiLo()) - - // PUSH BC - case 0xC5: - gb.pushStack(gb.CPU.BC.HiLo()) - - // PUSH DE - case 0xD5: - gb.pushStack(gb.CPU.DE.HiLo()) - - // PUSH HL - case 0xE5: - gb.pushStack(gb.CPU.HL.HiLo()) - - // POP AF - case 0xF1: - gb.CPU.AF.Set(gb.popStack()) - - // POP BC - case 0xC1: - gb.CPU.BC.Set(gb.popStack()) - - // POP DE - case 0xD1: - gb.CPU.DE.Set(gb.popStack()) - - // POP HL - case 0xE1: - gb.CPU.HL.Set(gb.popStack()) - - // ========== 8-Bit ALU =========== - - // ADD A,A - case 0x87: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) - - // ADD A,B - case 0x80: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), false) - - // ADD A,C - case 0x81: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), false) - - // ADD A,D - case 0x82: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), false) - - // ADD A,E - case 0x83: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), false) - - // ADD A,H - case 0x84: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), false) - - // ADD A,L - case 0x85: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), false) - - // ADD A,(HL) - case 0x86: - gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), false) - - // ADD A,# - case 0xC6: - gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), false) - - // ADC A,A - case 0x8F: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) - - // ADC A,B - case 0x88: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), true) - - // ADC A,C - case 0x89: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), true) - - // ADC A,D - case 0x8A: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), true) - - // ADC A,E - case 0x8B: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), true) - - // ADC A,H - case 0x8C: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), true) - - // ADC A,L - case 0x8D: - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), true) - - // ADC A,(HL) - case 0x8E: - gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), true) - - // ADC A,# - case 0xCE: - gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), true) - - // SUB A,A - case 0x97: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) - - // SUB A,B - case 0x90: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), false) - - // SUB A,C - case 0x91: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), false) - - // SUB A,D - case 0x92: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), false) - - // SUB A,E - case 0x93: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), false) - - // SUB A,H - case 0x94: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), false) - - // SUB A,L - case 0x95: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), false) - - // SUB A,(HL) - case 0x96: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), false) - - // SUB A,# - case 0xD6: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), false) - - // SBC A,A - case 0x9F: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) - - // SBC A,B - case 0x98: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), true) - - // SBC A,C - case 0x99: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), true) - - // SBC A,D - case 0x9A: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), true) - - // SBC A,E - case 0x9B: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), true) - - // SBC A,H - case 0x9C: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), true) - - // SBC A,L - case 0x9D: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), true) - - // SBC A,(HL) - case 0x9E: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), true) - - // SBC A,# - case 0xDE: - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), true) - - // AND A,A - case 0xA7: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - // AND A,B - case 0xA0: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - // AND A,C - case 0xA1: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - // AND A,D - case 0xA2: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - // AND A,E - case 0xA3: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - // AND A,H - case 0xA4: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - // AND A,L - case 0xA5: - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - // AND A,(HL) - case 0xA6: - gb.instAnd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - // AND A,# - case 0xE6: - gb.instAnd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - // OR A,A - case 0xB7: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - // OR A,B - case 0xB0: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - // OR A,C - case 0xB1: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - // OR A,D - case 0xB2: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - // OR A,E - case 0xB3: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - // OR A,H - case 0xB4: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - // OR A,L - case 0xB5: - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - // OR A,(HL) - case 0xB6: - gb.instOr(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - // OR A,# - case 0xF6: - gb.instOr(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - // XOR A,A - case 0xAF: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - // XOR A,B - case 0xA8: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - // XOR A,C - case 0xA9: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - // XOR A,D - case 0xAA: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - // XOR A,E - case 0xAB: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - // XOR A,H - case 0xAC: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - // XOR A,L - case 0xAD: - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - // XOR A,(HL) - case 0xAE: - gb.instXor(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - // XOR A,# - case 0xEE: - gb.instXor(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - // CP A,A - case 0xBF: - gb.instCp(gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - // CP A,B - case 0xB8: - gb.instCp(gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - // CP A,C - case 0xB9: - gb.instCp(gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - // CP A,D - case 0xBA: - gb.instCp(gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - // CP A,E - case 0xBB: - gb.instCp(gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - // CP A,H - case 0xBC: - gb.instCp(gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - // CP A,L - case 0xBD: - gb.instCp(gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - // CP A,(HL) - case 0xBE: - gb.instCp(gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - // CP A,# - case 0xFE: - gb.instCp(gb.popPC(), gb.CPU.AF.Hi()) - - // INC A - case 0x3C: - gb.instInc(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) - - // INC B - case 0x04: - gb.instInc(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) - - // INC C - case 0x0C: - gb.instInc(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) - - // INC D - case 0x14: - gb.instInc(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) - - // INC E - case 0x1C: - gb.instInc(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) - - // INC H - case 0x24: - gb.instInc(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) - - // INC L - case 0x2C: - gb.instInc(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) - - // INC (HL) - case 0x34: - addr := gb.CPU.HL.HiLo() - gb.instInc(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) - - // DEC A - case 0x3D: - gb.instDec(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) - - // DEC B - case 0x05: - gb.instDec(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) - - // DEC C - case 0x0D: - gb.instDec(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) - - // DEC D - case 0x15: - gb.instDec(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) - - // DEC E - case 0x1D: - gb.instDec(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) - - // DEC H - case 0x25: - gb.instDec(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) - - // DEC L - case 0x2D: - gb.instDec(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) - - // DEC (HL) - case 0x35: - addr := gb.CPU.HL.HiLo() - gb.instDec(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) - - // ========== 16-Bit ALU =========== - - // ADD HL,BC - case 0x09: - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.BC.HiLo()) - - // ADD HL,DE - case 0x19: - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.DE.HiLo()) - - // ADD HL,HL - case 0x29: - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.HL.HiLo()) - - // ADD HL,SP - case 0x39: - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.SP.HiLo()) - - // ADD SP,n - case 0xE8: - gb.instAdd16Signed(gb.CPU.SP.Set, gb.CPU.SP.HiLo(), int8(gb.popPC())) - gb.CPU.SetZ(false) - - // INC BC - case 0x03: - gb.instInc16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) - - // INC DE - case 0x13: - gb.instInc16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) - - // INC HL - case 0x23: - gb.instInc16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) - - // INC SP - case 0x33: - gb.instInc16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) - - // DEC BC - case 0x0B: - gb.instDec16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) - - // DEC DE - case 0x1B: - gb.instDec16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) - - // DEC HL - case 0x2B: - gb.instDec16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) - - // DEC SP - case 0x3B: - gb.instDec16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) - - // DAA - case 0x27: - /* - When this instruction is executed, the A register is BCD - corrected using the contents of the flags. The exact process - is the following: if the least significant four bits of A - contain a non-BCD digit (i. e. it is greater than 9) or the - H flag is set, then $06 is added to the register. Then the - four most significant bits are checked. If this more significant - digit also happens to be greater than 9 or the C flag is set, - then $60 is added. - */ - // TODO: This could be more efficient? - if !gb.CPU.N() { - if gb.CPU.C() || gb.CPU.AF.Hi() > 0x99 { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x60) - gb.CPU.SetC(true) - } - if gb.CPU.H() || gb.CPU.AF.Hi()&0xF > 0x9 { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x06) - gb.CPU.SetH(false) - } - } else if gb.CPU.C() && gb.CPU.H() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x9A) - gb.CPU.SetH(false) - } else if gb.CPU.C() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xA0) - } else if gb.CPU.H() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xFA) - gb.CPU.SetH(false) - } - gb.CPU.SetZ(gb.CPU.AF.Hi() == 0) - - // CPL - case 0x2F: - gb.CPU.AF.SetHi(0xFF ^ gb.CPU.AF.Hi()) - gb.CPU.SetN(true) - gb.CPU.SetH(true) - - // CCF - case 0x3F: - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(!gb.CPU.C()) - - // SCF - case 0x37: - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(true) - - // NOP - case 0x00: - break - - // HALT - case 0x76: - gb.halted = true - - // STOP - case 0x10: - //gb.halted = true - log.Print("0x10 (STOP) unimplemented (is 0x00 follows)") - - // DI - case 0xF3: - gb.interruptsOn = false - - // EI - case 0xFB: - gb.interruptsEnabling = true - - // RLCA - case 0x07: - value := gb.CPU.AF.Hi() - result := byte(value<<1) | (value >> 7) - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(value > 0x7F) - - // RLA - case 0x17: - value := gb.CPU.AF.Hi() - var carry byte - if gb.CPU.C() { - carry = 1 - } - result := byte(value<<1) + carry - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(value > 0x7F) - - // RRCA - case 0x0F: - value := gb.CPU.AF.Hi() - result := byte(value>>1) | byte((value&1)<<7) - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(result > 0x7F) - - // RRA - case 0x1F: - value := gb.CPU.AF.Hi() - var carry byte - if gb.CPU.C() { - carry = 0x80 - } - result := byte(value>>1) | carry - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC((1 & value) == 1) - - // JP nn - case 0xC3: - gb.instJump(gb.popPC16()) - - // JP NZ,nn - case 0xC2: - next := gb.popPC16() - if !gb.CPU.Z() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - // JP Z,nn - case 0xCA: - next := gb.popPC16() - if gb.CPU.Z() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - // JP NC,nn - case 0xD2: - next := gb.popPC16() - if !gb.CPU.C() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - // JP C,nn - case 0xDA: - next := gb.popPC16() - if gb.CPU.C() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - // JP HL - case 0xE9: - gb.instJump(gb.CPU.HL.HiLo()) - - // JR n - case 0x18: - addr := int32(gb.CPU.PC) + int32(int8(gb.popPC())) - gb.instJump(uint16(addr)) - - // JR NZ,n - case 0x20: - next := int8(gb.popPC()) - if !gb.CPU.Z() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - // JR Z,n - case 0x28: - next := int8(gb.popPC()) - if gb.CPU.Z() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - // JR NC,n - case 0x30: - next := int8(gb.popPC()) - if !gb.CPU.C() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - // JR C,n - case 0x38: - next := int8(gb.popPC()) - if gb.CPU.C() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - // CALL nn - case 0xCD: - gb.instCall(gb.popPC16()) - - // CALL NZ,nn - case 0xC4: - next := gb.popPC16() - if !gb.CPU.Z() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - // CALL Z,nn - case 0xCC: - next := gb.popPC16() - if gb.CPU.Z() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - // CALL NC,nn - case 0xD4: - next := gb.popPC16() - if !gb.CPU.C() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - // CALL C,nn - case 0xDC: - next := gb.popPC16() - if gb.CPU.C() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - // RST 0x00 - case 0xC7: - gb.instCall(0x0000) - - // RST 0x08 - case 0xCF: - gb.instCall(0x0008) - - // RST 0x10 - case 0xD7: - gb.instCall(0x0010) - - // RST 0x18 - case 0xDF: - gb.instCall(0x0018) - - // RST 0x20 - case 0xE7: - gb.instCall(0x0020) - - // RST 0x28 - case 0xEF: - gb.instCall(0x0028) - - // RST 0x30 - case 0xF7: - gb.instCall(0x0030) - - // RST 0x38 - case 0xFF: - gb.instCall(0x0038) - - // RET - case 0xC9: - gb.instRet() - - // RET NZ - case 0xC0: - if !gb.CPU.Z() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - // RET Z - case 0xC8: - if gb.CPU.Z() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - // RET NC - case 0xD0: - if !gb.CPU.C() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - // RET C - case 0xD8: - if gb.CPU.C() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - // RETI - case 0xD9: - gb.instRet() - gb.interruptsEnabling = true - - // CB - case 0xCB: - nextInst := gb.popPC() - gb.thisCpuTicks += CBOpcodeCycles[nextInst] * 4 - gb.cbInst[nextInst]() - - default: - log.Printf("Unimplemented opcode: %#2x", opcode) - WaitForInput() - } + gb.mainInst[opcode]() } diff --git a/pkg/gb/instructions_cb.go b/pkg/gb/instructions_cb.go index 705b9c1..2b1491e 100644 --- a/pkg/gb/instructions_cb.go +++ b/pkg/gb/instructions_cb.go @@ -98,10 +98,10 @@ func (gb *Gameboy) instSwap(setter func(byte), val byte) { gb.CPU.SetC(false) } -func (gb *Gameboy) cbInstructions() []func() { - instructions := make([]func(), 0x100) +func (gb *Gameboy) cbInstructions() [0x100]func() { + instructions := [0x100]func(){} - getMap := []func() byte{ + getMap := [8]func() byte{ gb.CPU.BC.Hi, gb.CPU.BC.Lo, gb.CPU.DE.Hi, @@ -111,7 +111,7 @@ func (gb *Gameboy) cbInstructions() []func() { func() byte { return gb.Memory.Read(gb.CPU.HL.HiLo()) }, gb.CPU.AF.Hi, } - setMap := []func(byte){ + setMap := [8]func(byte){ gb.CPU.BC.SetHi, gb.CPU.BC.SetLo, gb.CPU.DE.SetHi, @@ -126,44 +126,45 @@ func (gb *Gameboy) cbInstructions() []func() { // Store x so it can be used in the function scopes var i = x - instructions[byte(0x00+i)] = func() { gb.instRlc(setMap[i], getMap[i]()) } - instructions[byte(0x08+i)] = func() { gb.instRrc(setMap[i], getMap[i]()) } - instructions[byte(0x10+i)] = func() { gb.instRl(setMap[i], getMap[i]()) } - instructions[byte(0x18+i)] = func() { gb.instRr(setMap[i], getMap[i]()) } - instructions[byte(0x20+i)] = func() { gb.instSla(setMap[i], getMap[i]()) } - instructions[byte(0x28+i)] = func() { gb.instSra(setMap[i], getMap[i]()) } - instructions[byte(0x30+i)] = func() { gb.instSwap(setMap[i], getMap[i]()) } - instructions[byte(0x38+i)] = func() { gb.instSrl(setMap[i], getMap[i]()) } + instructions[0x00+i] = func() { gb.instRlc(setMap[i], getMap[i]()) } + instructions[0x08+i] = func() { gb.instRrc(setMap[i], getMap[i]()) } + instructions[0x10+i] = func() { gb.instRl(setMap[i], getMap[i]()) } + instructions[0x18+i] = func() { gb.instRr(setMap[i], getMap[i]()) } + instructions[0x20+i] = func() { gb.instSla(setMap[i], getMap[i]()) } + instructions[0x28+i] = func() { gb.instSra(setMap[i], getMap[i]()) } + instructions[0x30+i] = func() { gb.instSwap(setMap[i], getMap[i]()) } + instructions[0x38+i] = func() { gb.instSrl(setMap[i], getMap[i]()) } // BIT instructions - instructions[byte(0x40+i)] = func() { gb.instBit(0, getMap[i]()) } - instructions[byte(0x48+i)] = func() { gb.instBit(1, getMap[i]()) } - instructions[byte(0x50+i)] = func() { gb.instBit(2, getMap[i]()) } - instructions[byte(0x58+i)] = func() { gb.instBit(3, getMap[i]()) } - instructions[byte(0x60+i)] = func() { gb.instBit(4, getMap[i]()) } - instructions[byte(0x68+i)] = func() { gb.instBit(5, getMap[i]()) } - instructions[byte(0x70+i)] = func() { gb.instBit(6, getMap[i]()) } - instructions[byte(0x78+i)] = func() { gb.instBit(7, getMap[i]()) } + instructions[0x40+i] = func() { gb.instBit(0, getMap[i]()) } + instructions[0x48+i] = func() { gb.instBit(1, getMap[i]()) } + instructions[0x50+i] = func() { gb.instBit(2, getMap[i]()) } + instructions[0x58+i] = func() { gb.instBit(3, getMap[i]()) } + instructions[0x60+i] = func() { gb.instBit(4, getMap[i]()) } + instructions[0x68+i] = func() { gb.instBit(5, getMap[i]()) } + instructions[0x70+i] = func() { gb.instBit(6, getMap[i]()) } + instructions[0x78+i] = func() { gb.instBit(7, getMap[i]()) } // RES instructions - instructions[byte(0x80+i)] = func() { setMap[i](bits.Reset(getMap[i](), 0)) } - instructions[byte(0x88+i)] = func() { setMap[i](bits.Reset(getMap[i](), 1)) } - instructions[byte(0x90+i)] = func() { setMap[i](bits.Reset(getMap[i](), 2)) } - instructions[byte(0x98+i)] = func() { setMap[i](bits.Reset(getMap[i](), 3)) } - instructions[byte(0xA0+i)] = func() { setMap[i](bits.Reset(getMap[i](), 4)) } - instructions[byte(0xA8+i)] = func() { setMap[i](bits.Reset(getMap[i](), 5)) } - instructions[byte(0xB0+i)] = func() { setMap[i](bits.Reset(getMap[i](), 6)) } - instructions[byte(0xB8+i)] = func() { setMap[i](bits.Reset(getMap[i](), 7)) } + instructions[0x80+i] = func() { setMap[i](bits.Reset(getMap[i](), 0)) } + instructions[0x88+i] = func() { setMap[i](bits.Reset(getMap[i](), 1)) } + instructions[0x90+i] = func() { setMap[i](bits.Reset(getMap[i](), 2)) } + instructions[0x98+i] = func() { setMap[i](bits.Reset(getMap[i](), 3)) } + instructions[0xA0+i] = func() { setMap[i](bits.Reset(getMap[i](), 4)) } + instructions[0xA8+i] = func() { setMap[i](bits.Reset(getMap[i](), 5)) } + instructions[0xB0+i] = func() { setMap[i](bits.Reset(getMap[i](), 6)) } + instructions[0xB8+i] = func() { setMap[i](bits.Reset(getMap[i](), 7)) } // SET instructions - instructions[byte(0xC0+i)] = func() { setMap[i](bits.Set(getMap[i](), 0)) } - instructions[byte(0xC8+i)] = func() { setMap[i](bits.Set(getMap[i](), 1)) } - instructions[byte(0xD0+i)] = func() { setMap[i](bits.Set(getMap[i](), 2)) } - instructions[byte(0xD8+i)] = func() { setMap[i](bits.Set(getMap[i](), 3)) } - instructions[byte(0xE0+i)] = func() { setMap[i](bits.Set(getMap[i](), 4)) } - instructions[byte(0xE8+i)] = func() { setMap[i](bits.Set(getMap[i](), 5)) } - instructions[byte(0xF0+i)] = func() { setMap[i](bits.Set(getMap[i](), 6)) } - instructions[byte(0xF8+i)] = func() { setMap[i](bits.Set(getMap[i](), 7)) } + instructions[0xC0+i] = func() { setMap[i](bits.Set(getMap[i](), 0)) } + instructions[0xC8+i] = func() { setMap[i](bits.Set(getMap[i](), 1)) } + instructions[0xD0+i] = func() { setMap[i](bits.Set(getMap[i](), 2)) } + instructions[0xD8+i] = func() { setMap[i](bits.Set(getMap[i](), 3)) } + instructions[0xE0+i] = func() { setMap[i](bits.Set(getMap[i](), 4)) } + instructions[0xE8+i] = func() { setMap[i](bits.Set(getMap[i](), 5)) } + instructions[0xF0+i] = func() { setMap[i](bits.Set(getMap[i](), 6)) } + instructions[0xF8+i] = func() { setMap[i](bits.Set(getMap[i](), 7)) } } + return instructions } diff --git a/pkg/gb/instructions_table.go b/pkg/gb/instructions_table.go new file mode 100644 index 0000000..2404470 --- /dev/null +++ b/pkg/gb/instructions_table.go @@ -0,0 +1,1443 @@ +package gb + +import ( + "log" +) + +// mainInstructions creates and returns a table of the main +// insruction set +func (gb *Gameboy) mainInstructions() [0x100]func() { + // TODO: possibly faster if we derefernce + // each register and gb methods in this scope + + // ret gets returned + ret := [0x100]func(){ + 0x06: func() { + // LD B, n + gb.CPU.BC.SetHi(gb.popPC()) + + }, + 0x0E: func() { + // LD C, n + gb.CPU.BC.SetLo(gb.popPC()) + + }, + 0x16: func() { + // LD D, n + gb.CPU.DE.SetHi(gb.popPC()) + + }, + 0x1E: func() { + // LD E, n + gb.CPU.DE.SetLo(gb.popPC()) + + }, + 0x26: func() { + // LD H, n + gb.CPU.HL.SetHi(gb.popPC()) + + }, + 0x2E: func() { + // LD L, n + gb.CPU.HL.SetLo(gb.popPC()) + + }, + 0x7F: func() { + // LD A,A + gb.CPU.AF.SetHi(gb.CPU.AF.Hi()) + + }, + 0x78: func() { + // LD A,B + gb.CPU.AF.SetHi(gb.CPU.BC.Hi()) + + }, + 0x79: func() { + // LD A,C + gb.CPU.AF.SetHi(gb.CPU.BC.Lo()) + + }, + 0x7A: func() { + // LD A,D + gb.CPU.AF.SetHi(gb.CPU.DE.Hi()) + + }, + 0x7B: func() { + // LD A,E + gb.CPU.AF.SetHi(gb.CPU.DE.Lo()) + + }, + 0x7C: func() { + // LD A,H + gb.CPU.AF.SetHi(gb.CPU.HL.Hi()) + + }, + 0x7D: func() { + // LD A,L + gb.CPU.AF.SetHi(gb.CPU.HL.Lo()) + + }, + 0x0A: func() { + // LD A,(BC) + val := gb.Memory.Read(gb.CPU.BC.HiLo()) + gb.CPU.AF.SetHi(val) + + }, + 0x1A: func() { + // LD A,(DE) + val := gb.Memory.Read(gb.CPU.DE.HiLo()) + gb.CPU.AF.SetHi(val) + + }, + 0x7E: func() { + // LD A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + + }, + 0xFA: func() { + // LD A,(nn) + val := gb.Memory.Read(gb.popPC16()) + gb.CPU.AF.SetHi(val) + + }, + 0x3E: func() { + // LD A,(nn) + val := gb.popPC() + gb.CPU.AF.SetHi(val) + + }, + 0x47: func() { + // LD B,A + gb.CPU.BC.SetHi(gb.CPU.AF.Hi()) + + }, + 0x40: func() { + // LD B,B + gb.CPU.BC.SetHi(gb.CPU.BC.Hi()) + + }, + 0x41: func() { + // LD B,C + gb.CPU.BC.SetHi(gb.CPU.BC.Lo()) + + }, + 0x42: func() { + // LD B,D + gb.CPU.BC.SetHi(gb.CPU.DE.Hi()) + + }, + 0x43: func() { + // LD B,E + gb.CPU.BC.SetHi(gb.CPU.DE.Lo()) + + }, + 0x44: func() { + // LD B,H + gb.CPU.BC.SetHi(gb.CPU.HL.Hi()) + + }, + 0x45: func() { + // LD B,L + gb.CPU.BC.SetHi(gb.CPU.HL.Lo()) + + }, + 0x46: func() { + // LD B,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.BC.SetHi(val) + + }, + 0x4F: func() { + // LD C,A + gb.CPU.BC.SetLo(gb.CPU.AF.Hi()) + + }, + 0x48: func() { + // LD C,B + gb.CPU.BC.SetLo(gb.CPU.BC.Hi()) + + }, + 0x49: func() { + // LD C,C + gb.CPU.BC.SetLo(gb.CPU.BC.Lo()) + + }, + 0x4A: func() { + // LD C,D + gb.CPU.BC.SetLo(gb.CPU.DE.Hi()) + + }, + 0x4B: func() { + // LD C,E + gb.CPU.BC.SetLo(gb.CPU.DE.Lo()) + + }, + 0x4C: func() { + // LD C,H + gb.CPU.BC.SetLo(gb.CPU.HL.Hi()) + + }, + 0x4D: func() { + // LD C,L + gb.CPU.BC.SetLo(gb.CPU.HL.Lo()) + + }, + 0x4E: func() { + // LD C,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.BC.SetLo(val) + + }, + 0x57: func() { + // LD D,A + gb.CPU.DE.SetHi(gb.CPU.AF.Hi()) + + }, + 0x50: func() { + // LD D,B + gb.CPU.DE.SetHi(gb.CPU.BC.Hi()) + + }, + 0x51: func() { + // LD D,C + gb.CPU.DE.SetHi(gb.CPU.BC.Lo()) + + }, + 0x52: func() { + // LD D,D + gb.CPU.DE.SetHi(gb.CPU.DE.Hi()) + + }, + 0x53: func() { + // LD D,E + gb.CPU.DE.SetHi(gb.CPU.DE.Lo()) + + }, + 0x54: func() { + // LD D,H + gb.CPU.DE.SetHi(gb.CPU.HL.Hi()) + + }, + 0x55: func() { + // LD D,L + gb.CPU.DE.SetHi(gb.CPU.HL.Lo()) + + }, + 0x56: func() { + // LD D,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.DE.SetHi(val) + + }, + 0x5F: func() { + // LD E,A + gb.CPU.DE.SetLo(gb.CPU.AF.Hi()) + + }, + 0x58: func() { + // LD E,B + gb.CPU.DE.SetLo(gb.CPU.BC.Hi()) + + }, + 0x59: func() { + // LD E,C + gb.CPU.DE.SetLo(gb.CPU.BC.Lo()) + + }, + 0x5A: func() { + // LD E,D + gb.CPU.DE.SetLo(gb.CPU.DE.Hi()) + + }, + 0x5B: func() { + // LD E,E + gb.CPU.DE.SetLo(gb.CPU.DE.Lo()) + + }, + 0x5C: func() { + // LD E,H + gb.CPU.DE.SetLo(gb.CPU.HL.Hi()) + + }, + 0x5D: func() { + // LD E,L + gb.CPU.DE.SetLo(gb.CPU.HL.Lo()) + + }, + 0x5E: func() { + // LD E,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.DE.SetLo(val) + + }, + 0x67: func() { + // LD H,A + gb.CPU.HL.SetHi(gb.CPU.AF.Hi()) + + }, + 0x60: func() { + // LD H,B + gb.CPU.HL.SetHi(gb.CPU.BC.Hi()) + + }, + 0x61: func() { + // LD H,C + gb.CPU.HL.SetHi(gb.CPU.BC.Lo()) + + }, + 0x62: func() { + // LD H,D + gb.CPU.HL.SetHi(gb.CPU.DE.Hi()) + + }, + 0x63: func() { + // LD H,E + gb.CPU.HL.SetHi(gb.CPU.DE.Lo()) + + }, + 0x64: func() { + // LD H,H + gb.CPU.HL.SetHi(gb.CPU.HL.Hi()) + + }, + 0x65: func() { + // LD H,L + gb.CPU.HL.SetHi(gb.CPU.HL.Lo()) + + }, + 0x66: func() { + // LD H,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.HL.SetHi(val) + + }, + 0x6F: func() { + // LD L,A + gb.CPU.HL.SetLo(gb.CPU.AF.Hi()) + + }, + 0x68: func() { + // LD L,B + gb.CPU.HL.SetLo(gb.CPU.BC.Hi()) + + }, + 0x69: func() { + // LD L,C + gb.CPU.HL.SetLo(gb.CPU.BC.Lo()) + + }, + 0x6A: func() { + // LD L,D + gb.CPU.HL.SetLo(gb.CPU.DE.Hi()) + + }, + 0x6B: func() { + // LD L,E + gb.CPU.HL.SetLo(gb.CPU.DE.Lo()) + + }, + 0x6C: func() { + // LD L,H + gb.CPU.HL.SetLo(gb.CPU.HL.Hi()) + + }, + 0x6D: func() { + // LD L,L + gb.CPU.HL.SetLo(gb.CPU.HL.Lo()) + + }, + 0x6E: func() { + // LD L,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.HL.SetLo(val) + + }, + 0x77: func() { + // LD (HL),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x70: func() { + // LD (HL),B + val := gb.CPU.BC.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x71: func() { + // LD (HL),C + val := gb.CPU.BC.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x72: func() { + // LD (HL),D + val := gb.CPU.DE.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x73: func() { + // LD (HL),E + val := gb.CPU.DE.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x74: func() { + // LD (HL),H + val := gb.CPU.HL.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x75: func() { + // LD (HL),L + val := gb.CPU.HL.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x36: func() { + // LD (HL),n 36 + val := gb.popPC() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + + }, + 0x02: func() { + // LD (BC),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.BC.HiLo(), val) + + }, + 0x12: func() { + // LD (DE),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.DE.HiLo(), val) + + }, + 0xEA: func() { + // LD (nn),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.popPC16(), val) + + }, + 0xF2: func() { + // LD A,(C) + val := 0xFF00 + uint16(gb.CPU.BC.Lo()) + gb.CPU.AF.SetHi(gb.Memory.Read(val)) + + }, + 0xE2: func() { + // LD (C),A + val := gb.CPU.AF.Hi() + mem := 0xFF00 + uint16(gb.CPU.BC.Lo()) + gb.Memory.Write(mem, val) + + }, + 0x3A: func() { + // LDD A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) + + }, + 0x32: func() { + // LDD (HL),A + val := gb.CPU.HL.HiLo() + gb.Memory.Write(val, gb.CPU.AF.Hi()) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) + + }, + 0x2A: func() { + // LDI A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) + + }, + 0x22: func() { + // LDI (HL),A + val := gb.CPU.HL.HiLo() + gb.Memory.Write(val, gb.CPU.AF.Hi()) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) + + }, + 0xE0: func() { + // LD (0xFF00+n),A + val := 0xFF00 + uint16(gb.popPC()) + gb.Memory.Write(val, gb.CPU.AF.Hi()) + + }, + 0xF0: func() { + // LD A,(0xFF00+n) + val := gb.Memory.ReadHighRam(0xFF00 + uint16(gb.popPC())) + gb.CPU.AF.SetHi(val) + + // ========== 16-Bit Loads =========== + }, + 0x01: func() { + // LD BC,nn + val := gb.popPC16() + gb.CPU.BC.Set(val) + + }, + 0x11: func() { + // LD DE,nn + val := gb.popPC16() + gb.CPU.DE.Set(val) + + }, + 0x21: func() { + // LD HL,nn + val := gb.popPC16() + gb.CPU.HL.Set(val) + + }, + 0x31: func() { + // LD SP,nn + val := gb.popPC16() + gb.CPU.SP.Set(val) + + }, + 0xF9: func() { + // LD SP,HL + val := gb.CPU.HL + gb.CPU.SP = val + + }, + 0xF8: func() { + // LD HL,SP+n + val1 := int32(gb.CPU.SP.HiLo()) + val2 := int32(int8(gb.popPC())) + result := val1 + val2 + gb.CPU.HL.Set(uint16(result)) + tempVal := val1 ^ val2 ^ result + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + // TODO: Probably check these + gb.CPU.SetH((tempVal & 0x10) == 0x10) + gb.CPU.SetC((tempVal & 0x100) == 0x100) + + }, + 0x08: func() { + // LD (nn),SP + address := gb.popPC16() + gb.Memory.Write(address, gb.CPU.SP.Lo()) + gb.Memory.Write(address+1, gb.CPU.SP.Hi()) + + }, + 0xF5: func() { + // PUSH AF + gb.pushStack(gb.CPU.AF.HiLo()) + + }, + 0xC5: func() { + // PUSH BC + gb.pushStack(gb.CPU.BC.HiLo()) + + }, + 0xD5: func() { + // PUSH DE + gb.pushStack(gb.CPU.DE.HiLo()) + + }, + 0xE5: func() { + // PUSH HL + gb.pushStack(gb.CPU.HL.HiLo()) + + }, + 0xF1: func() { + // POP AF + gb.CPU.AF.Set(gb.popStack()) + + }, + 0xC1: func() { + // POP BC + gb.CPU.BC.Set(gb.popStack()) + + }, + 0xD1: func() { + // POP DE + gb.CPU.DE.Set(gb.popStack()) + + }, + 0xE1: func() { + // POP HL + gb.CPU.HL.Set(gb.popStack()) + + // ========== 8-Bit ALU =========== + }, + 0x87: func() { + // ADD A,A + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) + + }, + 0x80: func() { + // ADD A,B + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), false) + + }, + 0x81: func() { + // ADD A,C + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), false) + + }, + 0x82: func() { + // ADD A,D + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), false) + + }, + 0x83: func() { + // ADD A,E + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), false) + + }, + 0x84: func() { + // ADD A,H + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), false) + + }, + 0x85: func() { + // ADD A,L + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), false) + + }, + 0x86: func() { + // ADD A,(HL) + gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), false) + + }, + 0xC6: func() { + // ADD A,# + gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), false) + + }, + 0x8F: func() { + // ADC A,A + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) + + }, + 0x88: func() { + // ADC A,B + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), true) + + }, + 0x89: func() { + // ADC A,C + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), true) + + }, + 0x8A: func() { + // ADC A,D + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), true) + + }, + 0x8B: func() { + // ADC A,E + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), true) + + }, + 0x8C: func() { + // ADC A,H + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), true) + + }, + 0x8D: func() { + // ADC A,L + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), true) + + }, + 0x8E: func() { + // ADC A,(HL) + gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), true) + + }, + 0xCE: func() { + // ADC A,# + gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), true) + + }, + 0x97: func() { + // SUB A,A + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) + + }, + 0x90: func() { + // SUB A,B + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), false) + + }, + 0x91: func() { + // SUB A,C + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), false) + + }, + 0x92: func() { + // SUB A,D + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), false) + + }, + 0x93: func() { + // SUB A,E + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), false) + + }, + 0x94: func() { + // SUB A,H + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), false) + + }, + 0x95: func() { + // SUB A,L + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), false) + + }, + 0x96: func() { + // SUB A,(HL) + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), false) + + }, + 0xD6: func() { + // SUB A,# + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), false) + + }, + 0x9F: func() { + // SBC A,A + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) + + }, + 0x98: func() { + // SBC A,B + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), true) + + }, + 0x99: func() { + // SBC A,C + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), true) + + }, + 0x9A: func() { + // SBC A,D + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), true) + + }, + 0x9B: func() { + // SBC A,E + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), true) + + }, + 0x9C: func() { + // SBC A,H + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), true) + + }, + 0x9D: func() { + // SBC A,L + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), true) + + }, + 0x9E: func() { + // SBC A,(HL) + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), true) + + }, + 0xDE: func() { + // SBC A,# + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), true) + + }, + 0xA7: func() { + // AND A,A + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA0: func() { + // AND A,B + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA1: func() { + // AND A,C + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + + }, + 0xA2: func() { + // AND A,D + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA3: func() { + // AND A,E + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + + }, + 0xA4: func() { + // AND A,H + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA5: func() { + // AND A,L + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + + }, + 0xA6: func() { + // AND A,(HL) + gb.instAnd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + + }, + 0xE6: func() { + // AND A,# + gb.instAnd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + + }, + 0xB7: func() { + // OR A,A + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB0: func() { + // OR A,B + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB1: func() { + // OR A,C + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + + }, + 0xB2: func() { + // OR A,D + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB3: func() { + // OR A,E + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + + }, + 0xB4: func() { + // OR A,H + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB5: func() { + // OR A,L + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + + }, + 0xB6: func() { + // OR A,(HL) + gb.instOr(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + + }, + 0xF6: func() { + // OR A,# + gb.instOr(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + + }, + 0xAF: func() { + // XOR A,A + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA8: func() { + // XOR A,B + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + + }, + 0xA9: func() { + // XOR A,C + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + + }, + 0xAA: func() { + // XOR A,D + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + + }, + 0xAB: func() { + // XOR A,E + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + + }, + 0xAC: func() { + // XOR A,H + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + + }, + 0xAD: func() { + // XOR A,L + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + + }, + 0xAE: func() { + // XOR A,(HL) + gb.instXor(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + + }, + 0xEE: func() { + // XOR A,# + gb.instXor(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + + }, + 0xBF: func() { + // CP A,A + gb.instCp(gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB8: func() { + // CP A,B + gb.instCp(gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + + }, + 0xB9: func() { + // CP A,C + gb.instCp(gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + + }, + 0xBA: func() { + // CP A,D + gb.instCp(gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + + }, + 0xBB: func() { + // CP A,E + gb.instCp(gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + + }, + 0xBC: func() { + // CP A,H + gb.instCp(gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + + }, + 0xBD: func() { + // CP A,L + gb.instCp(gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + + }, + 0xBE: func() { + // CP A,(HL) + gb.instCp(gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + + }, + 0xFE: func() { + // CP A,# + gb.instCp(gb.popPC(), gb.CPU.AF.Hi()) + + }, + 0x3C: func() { + // INC A + gb.instInc(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) + + }, + 0x04: func() { + // INC B + gb.instInc(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) + + }, + 0x0C: func() { + // INC C + gb.instInc(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) + + }, + 0x14: func() { + // INC D + gb.instInc(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) + + }, + 0x1C: func() { + // INC E + gb.instInc(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) + + }, + 0x24: func() { + // INC H + gb.instInc(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) + + }, + 0x2C: func() { + // INC L + gb.instInc(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) + + }, + 0x34: func() { + // INC (HL) + addr := gb.CPU.HL.HiLo() + gb.instInc(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) + + }, + 0x3D: func() { + // DEC A + gb.instDec(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) + + }, + 0x05: func() { + // DEC B + gb.instDec(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) + + }, + 0x0D: func() { + // DEC C + gb.instDec(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) + + }, + 0x15: func() { + // DEC D + gb.instDec(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) + + }, + 0x1D: func() { + // DEC E + gb.instDec(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) + + }, + 0x25: func() { + // DEC H + gb.instDec(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) + + }, + 0x2D: func() { + // DEC L + gb.instDec(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) + + }, + 0x35: func() { + // DEC (HL) + addr := gb.CPU.HL.HiLo() + gb.instDec(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) + + // ========== 16-Bit ALU =========== + }, + 0x09: func() { + // ADD HL,BC + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.BC.HiLo()) + + }, + 0x19: func() { + // ADD HL,DE + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.DE.HiLo()) + + }, + 0x29: func() { + // ADD HL,HL + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.HL.HiLo()) + + }, + 0x39: func() { + // ADD HL,SP + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.SP.HiLo()) + + }, + 0xE8: func() { + // ADD SP,n + gb.instAdd16Signed(gb.CPU.SP.Set, gb.CPU.SP.HiLo(), int8(gb.popPC())) + gb.CPU.SetZ(false) + + }, + 0x03: func() { + // INC BC + gb.instInc16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) + + }, + 0x13: func() { + // INC DE + gb.instInc16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) + + }, + 0x23: func() { + // INC HL + gb.instInc16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) + + }, + 0x33: func() { + // INC SP + gb.instInc16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) + + }, + 0x0B: func() { + // DEC BC + gb.instDec16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) + + }, + 0x1B: func() { + // DEC DE + gb.instDec16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) + + }, + 0x2B: func() { + // DEC HL + gb.instDec16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) + + }, + 0x3B: func() { + // DEC SP + gb.instDec16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) + + }, + 0x27: func() { /* + // DAA + When this instruction is executed, the A register is BCD + corrected using the contents of the flags. The exact process + is the following: if the least significant four bits of A + contain a non-BCD digit (i. e. it is greater than 9) or the + H flag is set, then $06 is added to the register. Then the + four most significant bits are checked. If this more significant + digit also happens to be greater than 9 or the C flag is set, + then $60 is added. + */ + if !gb.CPU.N() { + // TODO: This could be more efficient? + if gb.CPU.C() || gb.CPU.AF.Hi() > 0x99 { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x60) + gb.CPU.SetC(true) + } + if gb.CPU.H() || gb.CPU.AF.Hi()&0xF > 0x9 { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x06) + gb.CPU.SetH(false) + } + } else if gb.CPU.C() && gb.CPU.H() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x9A) + gb.CPU.SetH(false) + } else if gb.CPU.C() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xA0) + } else if gb.CPU.H() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xFA) + gb.CPU.SetH(false) + } + gb.CPU.SetZ(gb.CPU.AF.Hi() == 0) + + }, + 0x2F: func() { + // CPL + gb.CPU.AF.SetHi(0xFF ^ gb.CPU.AF.Hi()) + gb.CPU.SetN(true) + gb.CPU.SetH(true) + + }, + 0x3F: func() { + // CCF + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(!gb.CPU.C()) + + }, + 0x37: func() { + // SCF + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(true) + + }, + 0x00: func() { + // NOP + + }, + 0x76: func() { + // HALT + gb.halted = true + + }, + 0x10: func() { //gb.halted = true + // STOP + log.Print("0x10 (STOP) unimplemented (is 0x00 follows)") + + }, + 0xF3: func() { + // DI + gb.interruptsOn = false + + }, + 0xFB: func() { + // EI + gb.interruptsEnabling = true + + }, + 0x07: func() { + // RLCA + value := gb.CPU.AF.Hi() + result := byte(value<<1) | (value >> 7) + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(value > 0x7F) + + }, + 0x17: func() { + // RLA + value := gb.CPU.AF.Hi() + var carry byte + if gb.CPU.C() { + carry = 1 + } + result := byte(value<<1) + carry + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(value > 0x7F) + + }, + 0x0F: func() { + // RRCA + value := gb.CPU.AF.Hi() + result := byte(value>>1) | byte((value&1)<<7) + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(result > 0x7F) + + }, + 0x1F: func() { + // RRA + value := gb.CPU.AF.Hi() + var carry byte + if gb.CPU.C() { + carry = 0x80 + } + result := byte(value>>1) | carry + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC((1 & value) == 1) + + }, + 0xC3: func() { + // JP nn + gb.instJump(gb.popPC16()) + + }, + 0xC2: func() { + // JP NZ,nn + next := gb.popPC16() + if !gb.CPU.Z() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + + }, + 0xCA: func() { + // JP Z,nn + next := gb.popPC16() + if gb.CPU.Z() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + + }, + 0xD2: func() { + // JP NC,nn + next := gb.popPC16() + if !gb.CPU.C() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + + }, + 0xDA: func() { + // JP C,nn + next := gb.popPC16() + if gb.CPU.C() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + + }, + 0xE9: func() { + // JP HL + gb.instJump(gb.CPU.HL.HiLo()) + + }, + 0x18: func() { + // JR n + addr := int32(gb.CPU.PC) + int32(int8(gb.popPC())) + gb.instJump(uint16(addr)) + + }, + 0x20: func() { + // JR NZ,n + next := int8(gb.popPC()) + if !gb.CPU.Z() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + + }, + 0x28: func() { + // JR Z,n + next := int8(gb.popPC()) + if gb.CPU.Z() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + + }, + 0x30: func() { + // JR NC,n + next := int8(gb.popPC()) + if !gb.CPU.C() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + + }, + 0x38: func() { + // JR C,n + next := int8(gb.popPC()) + if gb.CPU.C() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + + }, + 0xCD: func() { + // CALL nn + gb.instCall(gb.popPC16()) + + }, + 0xC4: func() { + // CALL NZ,nn + next := gb.popPC16() + if !gb.CPU.Z() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + + }, + 0xCC: func() { + // CALL Z,nn + next := gb.popPC16() + if gb.CPU.Z() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + + }, + 0xD4: func() { + // CALL NC,nn + next := gb.popPC16() + if !gb.CPU.C() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + + }, + 0xDC: func() { + // CALL C,nn + next := gb.popPC16() + if gb.CPU.C() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + + }, + 0xC7: func() { + // RST 0x00 + gb.instCall(0x0000) + + }, + 0xCF: func() { + // RST 0x08 + gb.instCall(0x0008) + + }, + 0xD7: func() { + // RST 0x10 + gb.instCall(0x0010) + + }, + 0xDF: func() { + // RST 0x18 + gb.instCall(0x0018) + + }, + 0xE7: func() { + // RST 0x20 + gb.instCall(0x0020) + + }, + 0xEF: func() { + // RST 0x28 + gb.instCall(0x0028) + + }, + 0xF7: func() { + // RST 0x30 + gb.instCall(0x0030) + + }, + 0xFF: func() { + // RST 0x38 + gb.instCall(0x0038) + + }, + 0xC9: func() { + // RET + gb.instRet() + + }, + 0xC0: func() { + // RET NZ + if !gb.CPU.Z() { + gb.instRet() + gb.thisCpuTicks += 12 + } + + }, + 0xC8: func() { + // RET Z + if gb.CPU.Z() { + gb.instRet() + gb.thisCpuTicks += 12 + } + + }, + 0xD0: func() { + // RET NC + if !gb.CPU.C() { + gb.instRet() + gb.thisCpuTicks += 12 + } + + }, + 0xD8: func() { + // RET C + if gb.CPU.C() { + gb.instRet() + gb.thisCpuTicks += 12 + } + + }, + 0xD9: func() { + // RETI + gb.instRet() + gb.interruptsEnabling = true + + }, + 0xCB: func() { + // CB + nextInst := gb.popPC() + gb.thisCpuTicks += CBOpcodeCycles[nextInst] * 4 + gb.cbInst[nextInst]() + }, + } + + // fill the empty elements of the array + // with a noop function to eliminate null checks + for k, v := range ret { + if v == nil { + ret[k] = func() { + log.Printf("Unimplemented opcode: %#2x", k) + WaitForInput() + } + } + } + + return ret +} From f936b661fca76b17075977e55459a4f1db19136e Mon Sep 17 00:00:00 2001 From: ear7h Date: Fri, 23 Nov 2018 15:11:19 -0800 Subject: [PATCH 2/3] variable scope bug fix for densifying the main instruction table --- pkg/gb/instructions_table.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/gb/instructions_table.go b/pkg/gb/instructions_table.go index 2404470..b44e0ef 100644 --- a/pkg/gb/instructions_table.go +++ b/pkg/gb/instructions_table.go @@ -1432,8 +1432,9 @@ func (gb *Gameboy) mainInstructions() [0x100]func() { // with a noop function to eliminate null checks for k, v := range ret { if v == nil { + opcode := k ret[k] = func() { - log.Printf("Unimplemented opcode: %#2x", k) + log.Printf("Unimplemented opcode: %#2x", opcode) WaitForInput() } } From 44458e2d9f401df7cb0b51b48bbc5c46363b8fd3 Mon Sep 17 00:00:00 2001 From: ear7h Date: Mon, 26 Nov 2018 21:06:57 -0800 Subject: [PATCH 3/3] fixed comments, removed ExecuteOpcode method, moved table creation to instructions.go, and minor style changes --- pkg/gb/gameboy.go | 6 +- pkg/gb/instructions.go | 1198 +++++++++++++++++++++++++++- pkg/gb/instructions_table.go | 1444 ---------------------------------- 3 files changed, 1196 insertions(+), 1452 deletions(-) delete mode 100644 pkg/gb/instructions_table.go diff --git a/pkg/gb/gameboy.go b/pkg/gb/gameboy.go index f59139c..9b6fe8d 100644 --- a/pkg/gb/gameboy.go +++ b/pkg/gb/gameboy.go @@ -50,11 +50,10 @@ type Gameboy struct { interruptsOn bool halted bool + mainInst [0x100]func() cbInst [0x100]func() InputMask byte - mainInst [0x100]func() - // Flag if the game is running in cgb mode. For this to be true the game // rom must support cgb mode and the option be true. cgbMode bool @@ -320,9 +319,8 @@ func (gb *Gameboy) setup() error { gb.scanlineCounter = 456 gb.InputMask = 0xFF - gb.cbInst = gb.cbInstructions() - gb.mainInst = gb.mainInstructions() + gb.cbInst = gb.cbInstructions() gb.SpritePalette = NewPalette() gb.BGPalette = NewPalette() diff --git a/pkg/gb/instructions.go b/pkg/gb/instructions.go index 21c1a52..c5cd4ce 100644 --- a/pkg/gb/instructions.go +++ b/pkg/gb/instructions.go @@ -1,5 +1,7 @@ package gb +import "log" + // OpcodeCycles is the number of cpu cycles for each normal opcode. var OpcodeCycles = []int{ 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 @@ -45,7 +47,7 @@ var CBOpcodeCycles = []int{ func (gb *Gameboy) ExecuteNextOpcode() int { opcode := gb.popPC() gb.thisCpuTicks = OpcodeCycles[opcode] * 4 - gb.ExecuteOpcode(opcode) + gb.mainInst[opcode]() return gb.thisCpuTicks } @@ -63,7 +65,1195 @@ func (gb *Gameboy) popPC16() uint16 { return b2<<8 | b1 } -// ExecuteOpcode is a large switch statement containing the opcode operations. -func (gb *Gameboy) ExecuteOpcode(opcode byte) { - gb.mainInst[opcode]() +// mainInstructions creates and returns a table of the main +// insruction set +func (gb *Gameboy) mainInstructions() [0x100]func() { + // TODO: possibly faster if we derefernce + // each register and gb methods in this scope + + // ret gets returned + ret := [0x100]func(){ + 0x06: func() { + // LD B, n + gb.CPU.BC.SetHi(gb.popPC()) + }, + 0x0E: func() { + // LD C, n + gb.CPU.BC.SetLo(gb.popPC()) + }, + 0x16: func() { + // LD D, n + gb.CPU.DE.SetHi(gb.popPC()) + }, + 0x1E: func() { + // LD E, n + gb.CPU.DE.SetLo(gb.popPC()) + }, + 0x26: func() { + // LD H, n + gb.CPU.HL.SetHi(gb.popPC()) + }, + 0x2E: func() { + // LD L, n + gb.CPU.HL.SetLo(gb.popPC()) + }, + 0x7F: func() { + // LD A,A + gb.CPU.AF.SetHi(gb.CPU.AF.Hi()) + }, + 0x78: func() { + // LD A,B + gb.CPU.AF.SetHi(gb.CPU.BC.Hi()) + }, + 0x79: func() { + // LD A,C + gb.CPU.AF.SetHi(gb.CPU.BC.Lo()) + }, + 0x7A: func() { + // LD A,D + gb.CPU.AF.SetHi(gb.CPU.DE.Hi()) + }, + 0x7B: func() { + // LD A,E + gb.CPU.AF.SetHi(gb.CPU.DE.Lo()) + }, + 0x7C: func() { + // LD A,H + gb.CPU.AF.SetHi(gb.CPU.HL.Hi()) + }, + 0x7D: func() { + // LD A,L + gb.CPU.AF.SetHi(gb.CPU.HL.Lo()) + }, + 0x0A: func() { + // LD A,(BC) + val := gb.Memory.Read(gb.CPU.BC.HiLo()) + gb.CPU.AF.SetHi(val) + }, + 0x1A: func() { + // LD A,(DE) + val := gb.Memory.Read(gb.CPU.DE.HiLo()) + gb.CPU.AF.SetHi(val) + }, + 0x7E: func() { + // LD A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + }, + 0xFA: func() { + // LD A,(nn) + val := gb.Memory.Read(gb.popPC16()) + gb.CPU.AF.SetHi(val) + }, + 0x3E: func() { + // LD A,(nn) + val := gb.popPC() + gb.CPU.AF.SetHi(val) + }, + 0x47: func() { + // LD B,A + gb.CPU.BC.SetHi(gb.CPU.AF.Hi()) + }, + 0x40: func() { + // LD B,B + gb.CPU.BC.SetHi(gb.CPU.BC.Hi()) + }, + 0x41: func() { + // LD B,C + gb.CPU.BC.SetHi(gb.CPU.BC.Lo()) + }, + 0x42: func() { + // LD B,D + gb.CPU.BC.SetHi(gb.CPU.DE.Hi()) + }, + 0x43: func() { + // LD B,E + gb.CPU.BC.SetHi(gb.CPU.DE.Lo()) + }, + 0x44: func() { + // LD B,H + gb.CPU.BC.SetHi(gb.CPU.HL.Hi()) + }, + 0x45: func() { + // LD B,L + gb.CPU.BC.SetHi(gb.CPU.HL.Lo()) + }, + 0x46: func() { + // LD B,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.BC.SetHi(val) + }, + 0x4F: func() { + // LD C,A + gb.CPU.BC.SetLo(gb.CPU.AF.Hi()) + }, + 0x48: func() { + // LD C,B + gb.CPU.BC.SetLo(gb.CPU.BC.Hi()) + }, + 0x49: func() { + // LD C,C + gb.CPU.BC.SetLo(gb.CPU.BC.Lo()) + }, + 0x4A: func() { + // LD C,D + gb.CPU.BC.SetLo(gb.CPU.DE.Hi()) + }, + 0x4B: func() { + // LD C,E + gb.CPU.BC.SetLo(gb.CPU.DE.Lo()) + }, + 0x4C: func() { + // LD C,H + gb.CPU.BC.SetLo(gb.CPU.HL.Hi()) + }, + 0x4D: func() { + // LD C,L + gb.CPU.BC.SetLo(gb.CPU.HL.Lo()) + }, + 0x4E: func() { + // LD C,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.BC.SetLo(val) + }, + 0x57: func() { + // LD D,A + gb.CPU.DE.SetHi(gb.CPU.AF.Hi()) + }, + 0x50: func() { + // LD D,B + gb.CPU.DE.SetHi(gb.CPU.BC.Hi()) + }, + 0x51: func() { + // LD D,C + gb.CPU.DE.SetHi(gb.CPU.BC.Lo()) + }, + 0x52: func() { + // LD D,D + gb.CPU.DE.SetHi(gb.CPU.DE.Hi()) + }, + 0x53: func() { + // LD D,E + gb.CPU.DE.SetHi(gb.CPU.DE.Lo()) + }, + 0x54: func() { + // LD D,H + gb.CPU.DE.SetHi(gb.CPU.HL.Hi()) + }, + 0x55: func() { + // LD D,L + gb.CPU.DE.SetHi(gb.CPU.HL.Lo()) + }, + 0x56: func() { + // LD D,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.DE.SetHi(val) + }, + 0x5F: func() { + // LD E,A + gb.CPU.DE.SetLo(gb.CPU.AF.Hi()) + }, + 0x58: func() { + // LD E,B + gb.CPU.DE.SetLo(gb.CPU.BC.Hi()) + }, + 0x59: func() { + // LD E,C + gb.CPU.DE.SetLo(gb.CPU.BC.Lo()) + }, + 0x5A: func() { + // LD E,D + gb.CPU.DE.SetLo(gb.CPU.DE.Hi()) + }, + 0x5B: func() { + // LD E,E + gb.CPU.DE.SetLo(gb.CPU.DE.Lo()) + }, + 0x5C: func() { + // LD E,H + gb.CPU.DE.SetLo(gb.CPU.HL.Hi()) + }, + 0x5D: func() { + // LD E,L + gb.CPU.DE.SetLo(gb.CPU.HL.Lo()) + }, + 0x5E: func() { + // LD E,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.DE.SetLo(val) + }, + 0x67: func() { + // LD H,A + gb.CPU.HL.SetHi(gb.CPU.AF.Hi()) + }, + 0x60: func() { + // LD H,B + gb.CPU.HL.SetHi(gb.CPU.BC.Hi()) + }, + 0x61: func() { + // LD H,C + gb.CPU.HL.SetHi(gb.CPU.BC.Lo()) + }, + 0x62: func() { + // LD H,D + gb.CPU.HL.SetHi(gb.CPU.DE.Hi()) + }, + 0x63: func() { + // LD H,E + gb.CPU.HL.SetHi(gb.CPU.DE.Lo()) + }, + 0x64: func() { + // LD H,H + gb.CPU.HL.SetHi(gb.CPU.HL.Hi()) + }, + 0x65: func() { + // LD H,L + gb.CPU.HL.SetHi(gb.CPU.HL.Lo()) + }, + 0x66: func() { + // LD H,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.HL.SetHi(val) + }, + 0x6F: func() { + // LD L,A + gb.CPU.HL.SetLo(gb.CPU.AF.Hi()) + }, + 0x68: func() { + // LD L,B + gb.CPU.HL.SetLo(gb.CPU.BC.Hi()) + }, + 0x69: func() { + // LD L,C + gb.CPU.HL.SetLo(gb.CPU.BC.Lo()) + }, + 0x6A: func() { + // LD L,D + gb.CPU.HL.SetLo(gb.CPU.DE.Hi()) + }, + 0x6B: func() { + // LD L,E + gb.CPU.HL.SetLo(gb.CPU.DE.Lo()) + }, + 0x6C: func() { + // LD L,H + gb.CPU.HL.SetLo(gb.CPU.HL.Hi()) + }, + 0x6D: func() { + // LD L,L + gb.CPU.HL.SetLo(gb.CPU.HL.Lo()) + }, + 0x6E: func() { + // LD L,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.HL.SetLo(val) + }, + 0x77: func() { + // LD (HL),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x70: func() { + // LD (HL),B + val := gb.CPU.BC.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x71: func() { + // LD (HL),C + val := gb.CPU.BC.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x72: func() { + // LD (HL),D + val := gb.CPU.DE.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x73: func() { + // LD (HL),E + val := gb.CPU.DE.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x74: func() { + // LD (HL),H + val := gb.CPU.HL.Hi() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x75: func() { + // LD (HL),L + val := gb.CPU.HL.Lo() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x36: func() { + // LD (HL),n 36 + val := gb.popPC() + gb.Memory.Write(gb.CPU.HL.HiLo(), val) + }, + 0x02: func() { + // LD (BC),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.BC.HiLo(), val) + }, + 0x12: func() { + // LD (DE),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.CPU.DE.HiLo(), val) + }, + 0xEA: func() { + // LD (nn),A + val := gb.CPU.AF.Hi() + gb.Memory.Write(gb.popPC16(), val) + }, + 0xF2: func() { + // LD A,(C) + val := 0xFF00 + uint16(gb.CPU.BC.Lo()) + gb.CPU.AF.SetHi(gb.Memory.Read(val)) + }, + 0xE2: func() { + // LD (C),A + val := gb.CPU.AF.Hi() + mem := 0xFF00 + uint16(gb.CPU.BC.Lo()) + gb.Memory.Write(mem, val) + }, + 0x3A: func() { + // LDD A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) + }, + 0x32: func() { + // LDD (HL),A + val := gb.CPU.HL.HiLo() + gb.Memory.Write(val, gb.CPU.AF.Hi()) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) + }, + 0x2A: func() { + // LDI A,(HL) + val := gb.Memory.Read(gb.CPU.HL.HiLo()) + gb.CPU.AF.SetHi(val) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) + }, + 0x22: func() { + // LDI (HL),A + val := gb.CPU.HL.HiLo() + gb.Memory.Write(val, gb.CPU.AF.Hi()) + gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) + }, + 0xE0: func() { + // LD (0xFF00+n),A + val := 0xFF00 + uint16(gb.popPC()) + gb.Memory.Write(val, gb.CPU.AF.Hi()) + }, + 0xF0: func() { + // LD A,(0xFF00+n) + val := gb.Memory.ReadHighRam(0xFF00 + uint16(gb.popPC())) + gb.CPU.AF.SetHi(val) + }, + // ========== 16-Bit Loads =========== + 0x01: func() { + // LD BC,nn + val := gb.popPC16() + gb.CPU.BC.Set(val) + }, + 0x11: func() { + // LD DE,nn + val := gb.popPC16() + gb.CPU.DE.Set(val) + }, + 0x21: func() { + // LD HL,nn + val := gb.popPC16() + gb.CPU.HL.Set(val) + }, + 0x31: func() { + // LD SP,nn + val := gb.popPC16() + gb.CPU.SP.Set(val) + }, + 0xF9: func() { + // LD SP,HL + val := gb.CPU.HL + gb.CPU.SP = val + }, + 0xF8: func() { + // LD HL,SP+n + val1 := int32(gb.CPU.SP.HiLo()) + val2 := int32(int8(gb.popPC())) + result := val1 + val2 + gb.CPU.HL.Set(uint16(result)) + tempVal := val1 ^ val2 ^ result + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + // TODO: Probably check these + gb.CPU.SetH((tempVal & 0x10) == 0x10) + gb.CPU.SetC((tempVal & 0x100) == 0x100) + }, + 0x08: func() { + // LD (nn),SP + address := gb.popPC16() + gb.Memory.Write(address, gb.CPU.SP.Lo()) + gb.Memory.Write(address+1, gb.CPU.SP.Hi()) + }, + 0xF5: func() { + // PUSH AF + gb.pushStack(gb.CPU.AF.HiLo()) + }, + 0xC5: func() { + // PUSH BC + gb.pushStack(gb.CPU.BC.HiLo()) + }, + 0xD5: func() { + // PUSH DE + gb.pushStack(gb.CPU.DE.HiLo()) + }, + 0xE5: func() { + // PUSH HL + gb.pushStack(gb.CPU.HL.HiLo()) + }, + 0xF1: func() { + // POP AF + gb.CPU.AF.Set(gb.popStack()) + }, + 0xC1: func() { + // POP BC + gb.CPU.BC.Set(gb.popStack()) + }, + 0xD1: func() { + // POP DE + gb.CPU.DE.Set(gb.popStack()) + }, + 0xE1: func() { + // POP HL + gb.CPU.HL.Set(gb.popStack()) + }, + // ========== 8-Bit ALU =========== + 0x87: func() { + // ADD A,A + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) + }, + 0x80: func() { + // ADD A,B + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), false) + }, + 0x81: func() { + // ADD A,C + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), false) + }, + 0x82: func() { + // ADD A,D + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), false) + }, + 0x83: func() { + // ADD A,E + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), false) + }, + 0x84: func() { + // ADD A,H + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), false) + }, + 0x85: func() { + // ADD A,L + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), false) + }, + 0x86: func() { + // ADD A,(HL) + gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), false) + }, + 0xC6: func() { + // ADD A,# + gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), false) + }, + 0x8F: func() { + // ADC A,A + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) + }, + 0x88: func() { + // ADC A,B + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), true) + }, + 0x89: func() { + // ADC A,C + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), true) + }, + 0x8A: func() { + // ADC A,D + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), true) + }, + 0x8B: func() { + // ADC A,E + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), true) + }, + 0x8C: func() { + // ADC A,H + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), true) + }, + 0x8D: func() { + // ADC A,L + gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), true) + }, + 0x8E: func() { + // ADC A,(HL) + gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), true) + }, + 0xCE: func() { + // ADC A,# + gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), true) + }, + 0x97: func() { + // SUB A,A + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) + }, + 0x90: func() { + // SUB A,B + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), false) + }, + 0x91: func() { + // SUB A,C + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), false) + }, + 0x92: func() { + // SUB A,D + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), false) + }, + 0x93: func() { + // SUB A,E + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), false) + }, + 0x94: func() { + // SUB A,H + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), false) + }, + 0x95: func() { + // SUB A,L + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), false) + }, + 0x96: func() { + // SUB A,(HL) + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), false) + }, + 0xD6: func() { + // SUB A,# + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), false) + }, + 0x9F: func() { + // SBC A,A + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) + }, + 0x98: func() { + // SBC A,B + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), true) + }, + 0x99: func() { + // SBC A,C + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), true) + }, + 0x9A: func() { + // SBC A,D + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), true) + }, + 0x9B: func() { + // SBC A,E + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), true) + }, + 0x9C: func() { + // SBC A,H + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), true) + }, + 0x9D: func() { + // SBC A,L + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), true) + }, + 0x9E: func() { + // SBC A,(HL) + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), true) + }, + 0xDE: func() { + // SBC A,# + gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), true) + }, + 0xA7: func() { + // AND A,A + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + }, + 0xA0: func() { + // AND A,B + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + }, + 0xA1: func() { + // AND A,C + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + }, + 0xA2: func() { + // AND A,D + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + }, + 0xA3: func() { + // AND A,E + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + }, + 0xA4: func() { + // AND A,H + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + }, + 0xA5: func() { + // AND A,L + gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + }, + 0xA6: func() { + // AND A,(HL) + gb.instAnd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + }, + 0xE6: func() { + // AND A,# + gb.instAnd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + }, + 0xB7: func() { + // OR A,A + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + }, + 0xB0: func() { + // OR A,B + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + }, + 0xB1: func() { + // OR A,C + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + }, + 0xB2: func() { + // OR A,D + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + }, + 0xB3: func() { + // OR A,E + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + }, + 0xB4: func() { + // OR A,H + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + }, + 0xB5: func() { + // OR A,L + gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + }, + 0xB6: func() { + // OR A,(HL) + gb.instOr(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + }, + 0xF6: func() { + // OR A,# + gb.instOr(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + }, + 0xAF: func() { + // XOR A,A + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + }, + 0xA8: func() { + // XOR A,B + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + }, + 0xA9: func() { + // XOR A,C + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + }, + 0xAA: func() { + // XOR A,D + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + }, + 0xAB: func() { + // XOR A,E + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + }, + 0xAC: func() { + // XOR A,H + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + }, + 0xAD: func() { + // XOR A,L + gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + }, + 0xAE: func() { + // XOR A,(HL) + gb.instXor(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + }, + 0xEE: func() { + // XOR A,# + gb.instXor(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) + }, + 0xBF: func() { + // CP A,A + gb.instCp(gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) + }, + 0xB8: func() { + // CP A,B + gb.instCp(gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) + }, + 0xB9: func() { + // CP A,C + gb.instCp(gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) + }, + 0xBA: func() { + // CP A,D + gb.instCp(gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) + }, + 0xBB: func() { + // CP A,E + gb.instCp(gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) + }, + 0xBC: func() { + // CP A,H + gb.instCp(gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) + }, + 0xBD: func() { + // CP A,L + gb.instCp(gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) + }, + 0xBE: func() { + // CP A,(HL) + gb.instCp(gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) + }, + 0xFE: func() { + // CP A,# + gb.instCp(gb.popPC(), gb.CPU.AF.Hi()) + }, + 0x3C: func() { + // INC A + gb.instInc(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) + }, + 0x04: func() { + // INC B + gb.instInc(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) + }, + 0x0C: func() { + // INC C + gb.instInc(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) + }, + 0x14: func() { + // INC D + gb.instInc(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) + }, + 0x1C: func() { + // INC E + gb.instInc(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) + }, + 0x24: func() { + // INC H + gb.instInc(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) + }, + 0x2C: func() { + // INC L + gb.instInc(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) + }, + 0x34: func() { + // INC (HL) + addr := gb.CPU.HL.HiLo() + gb.instInc(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) + }, + 0x3D: func() { + // DEC A + gb.instDec(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) + }, + 0x05: func() { + // DEC B + gb.instDec(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) + }, + 0x0D: func() { + // DEC C + gb.instDec(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) + }, + 0x15: func() { + // DEC D + gb.instDec(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) + }, + 0x1D: func() { + // DEC E + gb.instDec(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) + }, + 0x25: func() { + // DEC H + gb.instDec(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) + }, + 0x2D: func() { + // DEC L + gb.instDec(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) + }, + 0x35: func() { + // DEC (HL) + addr := gb.CPU.HL.HiLo() + gb.instDec(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) + }, + // ========== 16-Bit ALU =========== + 0x09: func() { + // ADD HL,BC + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.BC.HiLo()) + }, + 0x19: func() { + // ADD HL,DE + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.DE.HiLo()) + }, + 0x29: func() { + // ADD HL,HL + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.HL.HiLo()) + }, + 0x39: func() { + // ADD HL,SP + gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.SP.HiLo()) + }, + 0xE8: func() { + // ADD SP,n + gb.instAdd16Signed(gb.CPU.SP.Set, gb.CPU.SP.HiLo(), int8(gb.popPC())) + gb.CPU.SetZ(false) + }, + 0x03: func() { + // INC BC + gb.instInc16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) + }, + 0x13: func() { + // INC DE + gb.instInc16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) + }, + 0x23: func() { + // INC HL + gb.instInc16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) + }, + 0x33: func() { + // INC SP + gb.instInc16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) + }, + 0x0B: func() { + // DEC BC + gb.instDec16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) + }, + 0x1B: func() { + // DEC DE + gb.instDec16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) + }, + 0x2B: func() { + // DEC HL + gb.instDec16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) + }, + 0x3B: func() { + // DEC SP + gb.instDec16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) + }, + 0x27: func() { + // DAA + // When this instruction is executed, the A register is BCD + // corrected using the contents of the flags. The exact process + // is the following: if the least significant four bits of A + // contain a non-BCD digit (i. e. it is greater than 9) or the + // H flag is set, then $06 is added to the register. Then the + // four most significant bits are checked. If this more significant + // digit also happens to be greater than 9 or the C flag is set, + // then $60 is added. + if !gb.CPU.N() { + // TODO: This could be more efficient? + if gb.CPU.C() || gb.CPU.AF.Hi() > 0x99 { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x60) + gb.CPU.SetC(true) + } + if gb.CPU.H() || gb.CPU.AF.Hi()&0xF > 0x9 { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x06) + gb.CPU.SetH(false) + } + } else if gb.CPU.C() && gb.CPU.H() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x9A) + gb.CPU.SetH(false) + } else if gb.CPU.C() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xA0) + } else if gb.CPU.H() { + gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xFA) + gb.CPU.SetH(false) + } + gb.CPU.SetZ(gb.CPU.AF.Hi() == 0) + }, + 0x2F: func() { + // CPL + gb.CPU.AF.SetHi(0xFF ^ gb.CPU.AF.Hi()) + gb.CPU.SetN(true) + gb.CPU.SetH(true) + }, + 0x3F: func() { + // CCF + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(!gb.CPU.C()) + }, + 0x37: func() { + // SCF + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(true) + }, + 0x00: func() { + // NOP + }, + 0x76: func() { + // HALT + gb.halted = true + }, + 0x10: func() { + // STOP + //gb.halted = true + log.Print("0x10 (STOP) unimplemented (is 0x00 follows)") + }, + 0xF3: func() { + // DI + gb.interruptsOn = false + }, + 0xFB: func() { + // EI + gb.interruptsEnabling = true + }, + 0x07: func() { + // RLCA + value := gb.CPU.AF.Hi() + result := byte(value<<1) | (value >> 7) + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(value > 0x7F) + }, + 0x17: func() { + // RLA + value := gb.CPU.AF.Hi() + var carry byte + if gb.CPU.C() { + carry = 1 + } + result := byte(value<<1) + carry + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(value > 0x7F) + }, + 0x0F: func() { + // RRCA + value := gb.CPU.AF.Hi() + result := byte(value>>1) | byte((value&1)<<7) + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC(result > 0x7F) + }, + 0x1F: func() { + // RRA + value := gb.CPU.AF.Hi() + var carry byte + if gb.CPU.C() { + carry = 0x80 + } + result := byte(value>>1) | carry + gb.CPU.AF.SetHi(result) + gb.CPU.SetZ(false) + gb.CPU.SetN(false) + gb.CPU.SetH(false) + gb.CPU.SetC((1 & value) == 1) + }, + 0xC3: func() { + // JP nn + gb.instJump(gb.popPC16()) + }, + 0xC2: func() { + // JP NZ,nn + next := gb.popPC16() + if !gb.CPU.Z() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + }, + 0xCA: func() { + // JP Z,nn + next := gb.popPC16() + if gb.CPU.Z() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + }, + 0xD2: func() { + // JP NC,nn + next := gb.popPC16() + if !gb.CPU.C() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + }, + 0xDA: func() { + // JP C,nn + next := gb.popPC16() + if gb.CPU.C() { + gb.instJump(next) + gb.thisCpuTicks += 4 + } + }, + 0xE9: func() { + // JP HL + gb.instJump(gb.CPU.HL.HiLo()) + }, + 0x18: func() { + // JR n + addr := int32(gb.CPU.PC) + int32(int8(gb.popPC())) + gb.instJump(uint16(addr)) + }, + 0x20: func() { + // JR NZ,n + next := int8(gb.popPC()) + if !gb.CPU.Z() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + }, + 0x28: func() { + // JR Z,n + next := int8(gb.popPC()) + if gb.CPU.Z() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + }, + 0x30: func() { + // JR NC,n + next := int8(gb.popPC()) + if !gb.CPU.C() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + }, + 0x38: func() { + // JR C,n + next := int8(gb.popPC()) + if gb.CPU.C() { + addr := int32(gb.CPU.PC) + int32(next) + gb.instJump(uint16(addr)) + gb.thisCpuTicks += 4 + } + }, + 0xCD: func() { + // CALL nn + gb.instCall(gb.popPC16()) + }, + 0xC4: func() { + // CALL NZ,nn + next := gb.popPC16() + if !gb.CPU.Z() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + }, + 0xCC: func() { + // CALL Z,nn + next := gb.popPC16() + if gb.CPU.Z() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + }, + 0xD4: func() { + // CALL NC,nn + next := gb.popPC16() + if !gb.CPU.C() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + }, + 0xDC: func() { + // CALL C,nn + next := gb.popPC16() + if gb.CPU.C() { + gb.instCall(next) + gb.thisCpuTicks += 12 + } + }, + 0xC7: func() { + // RST 0x00 + gb.instCall(0x0000) + }, + 0xCF: func() { + // RST 0x08 + gb.instCall(0x0008) + }, + 0xD7: func() { + // RST 0x10 + gb.instCall(0x0010) + }, + 0xDF: func() { + // RST 0x18 + gb.instCall(0x0018) + }, + 0xE7: func() { + // RST 0x20 + gb.instCall(0x0020) + }, + 0xEF: func() { + // RST 0x28 + gb.instCall(0x0028) + }, + 0xF7: func() { + // RST 0x30 + gb.instCall(0x0030) + }, + 0xFF: func() { + // RST 0x38 + gb.instCall(0x0038) + }, + 0xC9: func() { + // RET + gb.instRet() + }, + 0xC0: func() { + // RET NZ + if !gb.CPU.Z() { + gb.instRet() + gb.thisCpuTicks += 12 + } + }, + 0xC8: func() { + // RET Z + if gb.CPU.Z() { + gb.instRet() + gb.thisCpuTicks += 12 + } + }, + 0xD0: func() { + // RET NC + if !gb.CPU.C() { + gb.instRet() + gb.thisCpuTicks += 12 + } + }, + 0xD8: func() { + // RET C + if gb.CPU.C() { + gb.instRet() + gb.thisCpuTicks += 12 + } + }, + 0xD9: func() { + // RETI + gb.instRet() + gb.interruptsEnabling = true + }, + 0xCB: func() { + // CB + nextInst := gb.popPC() + gb.thisCpuTicks += CBOpcodeCycles[nextInst] * 4 + gb.cbInst[nextInst]() + }, + } + // fill the empty elements of the array + // with a noop function to eliminate null checks + for k, v := range ret { + if v == nil { + opcode := k + ret[k] = func() { + log.Printf("Unimplemented opcode: %#2x", opcode) + WaitForInput() + } + } + } + return ret } diff --git a/pkg/gb/instructions_table.go b/pkg/gb/instructions_table.go deleted file mode 100644 index b44e0ef..0000000 --- a/pkg/gb/instructions_table.go +++ /dev/null @@ -1,1444 +0,0 @@ -package gb - -import ( - "log" -) - -// mainInstructions creates and returns a table of the main -// insruction set -func (gb *Gameboy) mainInstructions() [0x100]func() { - // TODO: possibly faster if we derefernce - // each register and gb methods in this scope - - // ret gets returned - ret := [0x100]func(){ - 0x06: func() { - // LD B, n - gb.CPU.BC.SetHi(gb.popPC()) - - }, - 0x0E: func() { - // LD C, n - gb.CPU.BC.SetLo(gb.popPC()) - - }, - 0x16: func() { - // LD D, n - gb.CPU.DE.SetHi(gb.popPC()) - - }, - 0x1E: func() { - // LD E, n - gb.CPU.DE.SetLo(gb.popPC()) - - }, - 0x26: func() { - // LD H, n - gb.CPU.HL.SetHi(gb.popPC()) - - }, - 0x2E: func() { - // LD L, n - gb.CPU.HL.SetLo(gb.popPC()) - - }, - 0x7F: func() { - // LD A,A - gb.CPU.AF.SetHi(gb.CPU.AF.Hi()) - - }, - 0x78: func() { - // LD A,B - gb.CPU.AF.SetHi(gb.CPU.BC.Hi()) - - }, - 0x79: func() { - // LD A,C - gb.CPU.AF.SetHi(gb.CPU.BC.Lo()) - - }, - 0x7A: func() { - // LD A,D - gb.CPU.AF.SetHi(gb.CPU.DE.Hi()) - - }, - 0x7B: func() { - // LD A,E - gb.CPU.AF.SetHi(gb.CPU.DE.Lo()) - - }, - 0x7C: func() { - // LD A,H - gb.CPU.AF.SetHi(gb.CPU.HL.Hi()) - - }, - 0x7D: func() { - // LD A,L - gb.CPU.AF.SetHi(gb.CPU.HL.Lo()) - - }, - 0x0A: func() { - // LD A,(BC) - val := gb.Memory.Read(gb.CPU.BC.HiLo()) - gb.CPU.AF.SetHi(val) - - }, - 0x1A: func() { - // LD A,(DE) - val := gb.Memory.Read(gb.CPU.DE.HiLo()) - gb.CPU.AF.SetHi(val) - - }, - 0x7E: func() { - // LD A,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - - }, - 0xFA: func() { - // LD A,(nn) - val := gb.Memory.Read(gb.popPC16()) - gb.CPU.AF.SetHi(val) - - }, - 0x3E: func() { - // LD A,(nn) - val := gb.popPC() - gb.CPU.AF.SetHi(val) - - }, - 0x47: func() { - // LD B,A - gb.CPU.BC.SetHi(gb.CPU.AF.Hi()) - - }, - 0x40: func() { - // LD B,B - gb.CPU.BC.SetHi(gb.CPU.BC.Hi()) - - }, - 0x41: func() { - // LD B,C - gb.CPU.BC.SetHi(gb.CPU.BC.Lo()) - - }, - 0x42: func() { - // LD B,D - gb.CPU.BC.SetHi(gb.CPU.DE.Hi()) - - }, - 0x43: func() { - // LD B,E - gb.CPU.BC.SetHi(gb.CPU.DE.Lo()) - - }, - 0x44: func() { - // LD B,H - gb.CPU.BC.SetHi(gb.CPU.HL.Hi()) - - }, - 0x45: func() { - // LD B,L - gb.CPU.BC.SetHi(gb.CPU.HL.Lo()) - - }, - 0x46: func() { - // LD B,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.BC.SetHi(val) - - }, - 0x4F: func() { - // LD C,A - gb.CPU.BC.SetLo(gb.CPU.AF.Hi()) - - }, - 0x48: func() { - // LD C,B - gb.CPU.BC.SetLo(gb.CPU.BC.Hi()) - - }, - 0x49: func() { - // LD C,C - gb.CPU.BC.SetLo(gb.CPU.BC.Lo()) - - }, - 0x4A: func() { - // LD C,D - gb.CPU.BC.SetLo(gb.CPU.DE.Hi()) - - }, - 0x4B: func() { - // LD C,E - gb.CPU.BC.SetLo(gb.CPU.DE.Lo()) - - }, - 0x4C: func() { - // LD C,H - gb.CPU.BC.SetLo(gb.CPU.HL.Hi()) - - }, - 0x4D: func() { - // LD C,L - gb.CPU.BC.SetLo(gb.CPU.HL.Lo()) - - }, - 0x4E: func() { - // LD C,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.BC.SetLo(val) - - }, - 0x57: func() { - // LD D,A - gb.CPU.DE.SetHi(gb.CPU.AF.Hi()) - - }, - 0x50: func() { - // LD D,B - gb.CPU.DE.SetHi(gb.CPU.BC.Hi()) - - }, - 0x51: func() { - // LD D,C - gb.CPU.DE.SetHi(gb.CPU.BC.Lo()) - - }, - 0x52: func() { - // LD D,D - gb.CPU.DE.SetHi(gb.CPU.DE.Hi()) - - }, - 0x53: func() { - // LD D,E - gb.CPU.DE.SetHi(gb.CPU.DE.Lo()) - - }, - 0x54: func() { - // LD D,H - gb.CPU.DE.SetHi(gb.CPU.HL.Hi()) - - }, - 0x55: func() { - // LD D,L - gb.CPU.DE.SetHi(gb.CPU.HL.Lo()) - - }, - 0x56: func() { - // LD D,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.DE.SetHi(val) - - }, - 0x5F: func() { - // LD E,A - gb.CPU.DE.SetLo(gb.CPU.AF.Hi()) - - }, - 0x58: func() { - // LD E,B - gb.CPU.DE.SetLo(gb.CPU.BC.Hi()) - - }, - 0x59: func() { - // LD E,C - gb.CPU.DE.SetLo(gb.CPU.BC.Lo()) - - }, - 0x5A: func() { - // LD E,D - gb.CPU.DE.SetLo(gb.CPU.DE.Hi()) - - }, - 0x5B: func() { - // LD E,E - gb.CPU.DE.SetLo(gb.CPU.DE.Lo()) - - }, - 0x5C: func() { - // LD E,H - gb.CPU.DE.SetLo(gb.CPU.HL.Hi()) - - }, - 0x5D: func() { - // LD E,L - gb.CPU.DE.SetLo(gb.CPU.HL.Lo()) - - }, - 0x5E: func() { - // LD E,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.DE.SetLo(val) - - }, - 0x67: func() { - // LD H,A - gb.CPU.HL.SetHi(gb.CPU.AF.Hi()) - - }, - 0x60: func() { - // LD H,B - gb.CPU.HL.SetHi(gb.CPU.BC.Hi()) - - }, - 0x61: func() { - // LD H,C - gb.CPU.HL.SetHi(gb.CPU.BC.Lo()) - - }, - 0x62: func() { - // LD H,D - gb.CPU.HL.SetHi(gb.CPU.DE.Hi()) - - }, - 0x63: func() { - // LD H,E - gb.CPU.HL.SetHi(gb.CPU.DE.Lo()) - - }, - 0x64: func() { - // LD H,H - gb.CPU.HL.SetHi(gb.CPU.HL.Hi()) - - }, - 0x65: func() { - // LD H,L - gb.CPU.HL.SetHi(gb.CPU.HL.Lo()) - - }, - 0x66: func() { - // LD H,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.HL.SetHi(val) - - }, - 0x6F: func() { - // LD L,A - gb.CPU.HL.SetLo(gb.CPU.AF.Hi()) - - }, - 0x68: func() { - // LD L,B - gb.CPU.HL.SetLo(gb.CPU.BC.Hi()) - - }, - 0x69: func() { - // LD L,C - gb.CPU.HL.SetLo(gb.CPU.BC.Lo()) - - }, - 0x6A: func() { - // LD L,D - gb.CPU.HL.SetLo(gb.CPU.DE.Hi()) - - }, - 0x6B: func() { - // LD L,E - gb.CPU.HL.SetLo(gb.CPU.DE.Lo()) - - }, - 0x6C: func() { - // LD L,H - gb.CPU.HL.SetLo(gb.CPU.HL.Hi()) - - }, - 0x6D: func() { - // LD L,L - gb.CPU.HL.SetLo(gb.CPU.HL.Lo()) - - }, - 0x6E: func() { - // LD L,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.HL.SetLo(val) - - }, - 0x77: func() { - // LD (HL),A - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x70: func() { - // LD (HL),B - val := gb.CPU.BC.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x71: func() { - // LD (HL),C - val := gb.CPU.BC.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x72: func() { - // LD (HL),D - val := gb.CPU.DE.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x73: func() { - // LD (HL),E - val := gb.CPU.DE.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x74: func() { - // LD (HL),H - val := gb.CPU.HL.Hi() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x75: func() { - // LD (HL),L - val := gb.CPU.HL.Lo() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x36: func() { - // LD (HL),n 36 - val := gb.popPC() - gb.Memory.Write(gb.CPU.HL.HiLo(), val) - - }, - 0x02: func() { - // LD (BC),A - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.BC.HiLo(), val) - - }, - 0x12: func() { - // LD (DE),A - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.CPU.DE.HiLo(), val) - - }, - 0xEA: func() { - // LD (nn),A - val := gb.CPU.AF.Hi() - gb.Memory.Write(gb.popPC16(), val) - - }, - 0xF2: func() { - // LD A,(C) - val := 0xFF00 + uint16(gb.CPU.BC.Lo()) - gb.CPU.AF.SetHi(gb.Memory.Read(val)) - - }, - 0xE2: func() { - // LD (C),A - val := gb.CPU.AF.Hi() - mem := 0xFF00 + uint16(gb.CPU.BC.Lo()) - gb.Memory.Write(mem, val) - - }, - 0x3A: func() { - // LDD A,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) - - }, - 0x32: func() { - // LDD (HL),A - val := gb.CPU.HL.HiLo() - gb.Memory.Write(val, gb.CPU.AF.Hi()) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() - 1) - - }, - 0x2A: func() { - // LDI A,(HL) - val := gb.Memory.Read(gb.CPU.HL.HiLo()) - gb.CPU.AF.SetHi(val) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) - - }, - 0x22: func() { - // LDI (HL),A - val := gb.CPU.HL.HiLo() - gb.Memory.Write(val, gb.CPU.AF.Hi()) - gb.CPU.HL.Set(gb.CPU.HL.HiLo() + 1) - - }, - 0xE0: func() { - // LD (0xFF00+n),A - val := 0xFF00 + uint16(gb.popPC()) - gb.Memory.Write(val, gb.CPU.AF.Hi()) - - }, - 0xF0: func() { - // LD A,(0xFF00+n) - val := gb.Memory.ReadHighRam(0xFF00 + uint16(gb.popPC())) - gb.CPU.AF.SetHi(val) - - // ========== 16-Bit Loads =========== - }, - 0x01: func() { - // LD BC,nn - val := gb.popPC16() - gb.CPU.BC.Set(val) - - }, - 0x11: func() { - // LD DE,nn - val := gb.popPC16() - gb.CPU.DE.Set(val) - - }, - 0x21: func() { - // LD HL,nn - val := gb.popPC16() - gb.CPU.HL.Set(val) - - }, - 0x31: func() { - // LD SP,nn - val := gb.popPC16() - gb.CPU.SP.Set(val) - - }, - 0xF9: func() { - // LD SP,HL - val := gb.CPU.HL - gb.CPU.SP = val - - }, - 0xF8: func() { - // LD HL,SP+n - val1 := int32(gb.CPU.SP.HiLo()) - val2 := int32(int8(gb.popPC())) - result := val1 + val2 - gb.CPU.HL.Set(uint16(result)) - tempVal := val1 ^ val2 ^ result - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - // TODO: Probably check these - gb.CPU.SetH((tempVal & 0x10) == 0x10) - gb.CPU.SetC((tempVal & 0x100) == 0x100) - - }, - 0x08: func() { - // LD (nn),SP - address := gb.popPC16() - gb.Memory.Write(address, gb.CPU.SP.Lo()) - gb.Memory.Write(address+1, gb.CPU.SP.Hi()) - - }, - 0xF5: func() { - // PUSH AF - gb.pushStack(gb.CPU.AF.HiLo()) - - }, - 0xC5: func() { - // PUSH BC - gb.pushStack(gb.CPU.BC.HiLo()) - - }, - 0xD5: func() { - // PUSH DE - gb.pushStack(gb.CPU.DE.HiLo()) - - }, - 0xE5: func() { - // PUSH HL - gb.pushStack(gb.CPU.HL.HiLo()) - - }, - 0xF1: func() { - // POP AF - gb.CPU.AF.Set(gb.popStack()) - - }, - 0xC1: func() { - // POP BC - gb.CPU.BC.Set(gb.popStack()) - - }, - 0xD1: func() { - // POP DE - gb.CPU.DE.Set(gb.popStack()) - - }, - 0xE1: func() { - // POP HL - gb.CPU.HL.Set(gb.popStack()) - - // ========== 8-Bit ALU =========== - }, - 0x87: func() { - // ADD A,A - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) - - }, - 0x80: func() { - // ADD A,B - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), false) - - }, - 0x81: func() { - // ADD A,C - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), false) - - }, - 0x82: func() { - // ADD A,D - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), false) - - }, - 0x83: func() { - // ADD A,E - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), false) - - }, - 0x84: func() { - // ADD A,H - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), false) - - }, - 0x85: func() { - // ADD A,L - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), false) - - }, - 0x86: func() { - // ADD A,(HL) - gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), false) - - }, - 0xC6: func() { - // ADD A,# - gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), false) - - }, - 0x8F: func() { - // ADC A,A - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) - - }, - 0x88: func() { - // ADC A,B - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi(), true) - - }, - 0x89: func() { - // ADC A,C - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi(), true) - - }, - 0x8A: func() { - // ADC A,D - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi(), true) - - }, - 0x8B: func() { - // ADC A,E - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi(), true) - - }, - 0x8C: func() { - // ADC A,H - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi(), true) - - }, - 0x8D: func() { - // ADC A,L - gb.instAdd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi(), true) - - }, - 0x8E: func() { - // ADC A,(HL) - gb.instAdd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi(), true) - - }, - 0xCE: func() { - // ADC A,# - gb.instAdd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi(), true) - - }, - 0x97: func() { - // SUB A,A - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), false) - - }, - 0x90: func() { - // SUB A,B - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), false) - - }, - 0x91: func() { - // SUB A,C - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), false) - - }, - 0x92: func() { - // SUB A,D - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), false) - - }, - 0x93: func() { - // SUB A,E - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), false) - - }, - 0x94: func() { - // SUB A,H - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), false) - - }, - 0x95: func() { - // SUB A,L - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), false) - - }, - 0x96: func() { - // SUB A,(HL) - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), false) - - }, - 0xD6: func() { - // SUB A,# - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), false) - - }, - 0x9F: func() { - // SBC A,A - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi(), true) - - }, - 0x98: func() { - // SBC A,B - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Hi(), true) - - }, - 0x99: func() { - // SBC A,C - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.BC.Lo(), true) - - }, - 0x9A: func() { - // SBC A,D - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Hi(), true) - - }, - 0x9B: func() { - // SBC A,E - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.DE.Lo(), true) - - }, - 0x9C: func() { - // SBC A,H - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Hi(), true) - - }, - 0x9D: func() { - // SBC A,L - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.HL.Lo(), true) - - }, - 0x9E: func() { - // SBC A,(HL) - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.Memory.Read(gb.CPU.HL.HiLo()), true) - - }, - 0xDE: func() { - // SBC A,# - gb.instSub(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.popPC(), true) - - }, - 0xA7: func() { - // AND A,A - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA0: func() { - // AND A,B - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA1: func() { - // AND A,C - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - }, - 0xA2: func() { - // AND A,D - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA3: func() { - // AND A,E - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - }, - 0xA4: func() { - // AND A,H - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA5: func() { - // AND A,L - gb.instAnd(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - }, - 0xA6: func() { - // AND A,(HL) - gb.instAnd(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - }, - 0xE6: func() { - // AND A,# - gb.instAnd(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - }, - 0xB7: func() { - // OR A,A - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB0: func() { - // OR A,B - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB1: func() { - // OR A,C - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - }, - 0xB2: func() { - // OR A,D - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB3: func() { - // OR A,E - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - }, - 0xB4: func() { - // OR A,H - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB5: func() { - // OR A,L - gb.instOr(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - }, - 0xB6: func() { - // OR A,(HL) - gb.instOr(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - }, - 0xF6: func() { - // OR A,# - gb.instOr(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - }, - 0xAF: func() { - // XOR A,A - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA8: func() { - // XOR A,B - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - }, - 0xA9: func() { - // XOR A,C - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - }, - 0xAA: func() { - // XOR A,D - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - }, - 0xAB: func() { - // XOR A,E - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - }, - 0xAC: func() { - // XOR A,H - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - }, - 0xAD: func() { - // XOR A,L - gb.instXor(gb.CPU.AF.SetHi, gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - }, - 0xAE: func() { - // XOR A,(HL) - gb.instXor(gb.CPU.AF.SetHi, gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - }, - 0xEE: func() { - // XOR A,# - gb.instXor(gb.CPU.AF.SetHi, gb.popPC(), gb.CPU.AF.Hi()) - - }, - 0xBF: func() { - // CP A,A - gb.instCp(gb.CPU.AF.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB8: func() { - // CP A,B - gb.instCp(gb.CPU.BC.Hi(), gb.CPU.AF.Hi()) - - }, - 0xB9: func() { - // CP A,C - gb.instCp(gb.CPU.BC.Lo(), gb.CPU.AF.Hi()) - - }, - 0xBA: func() { - // CP A,D - gb.instCp(gb.CPU.DE.Hi(), gb.CPU.AF.Hi()) - - }, - 0xBB: func() { - // CP A,E - gb.instCp(gb.CPU.DE.Lo(), gb.CPU.AF.Hi()) - - }, - 0xBC: func() { - // CP A,H - gb.instCp(gb.CPU.HL.Hi(), gb.CPU.AF.Hi()) - - }, - 0xBD: func() { - // CP A,L - gb.instCp(gb.CPU.HL.Lo(), gb.CPU.AF.Hi()) - - }, - 0xBE: func() { - // CP A,(HL) - gb.instCp(gb.Memory.Read(gb.CPU.HL.HiLo()), gb.CPU.AF.Hi()) - - }, - 0xFE: func() { - // CP A,# - gb.instCp(gb.popPC(), gb.CPU.AF.Hi()) - - }, - 0x3C: func() { - // INC A - gb.instInc(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) - - }, - 0x04: func() { - // INC B - gb.instInc(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) - - }, - 0x0C: func() { - // INC C - gb.instInc(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) - - }, - 0x14: func() { - // INC D - gb.instInc(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) - - }, - 0x1C: func() { - // INC E - gb.instInc(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) - - }, - 0x24: func() { - // INC H - gb.instInc(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) - - }, - 0x2C: func() { - // INC L - gb.instInc(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) - - }, - 0x34: func() { - // INC (HL) - addr := gb.CPU.HL.HiLo() - gb.instInc(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) - - }, - 0x3D: func() { - // DEC A - gb.instDec(gb.CPU.AF.SetHi, gb.CPU.AF.Hi()) - - }, - 0x05: func() { - // DEC B - gb.instDec(gb.CPU.BC.SetHi, gb.CPU.BC.Hi()) - - }, - 0x0D: func() { - // DEC C - gb.instDec(gb.CPU.BC.SetLo, gb.CPU.BC.Lo()) - - }, - 0x15: func() { - // DEC D - gb.instDec(gb.CPU.DE.SetHi, gb.CPU.DE.Hi()) - - }, - 0x1D: func() { - // DEC E - gb.instDec(gb.CPU.DE.SetLo, gb.CPU.DE.Lo()) - - }, - 0x25: func() { - // DEC H - gb.instDec(gb.CPU.HL.SetHi, gb.CPU.HL.Hi()) - - }, - 0x2D: func() { - // DEC L - gb.instDec(gb.CPU.HL.SetLo, gb.CPU.HL.Lo()) - - }, - 0x35: func() { - // DEC (HL) - addr := gb.CPU.HL.HiLo() - gb.instDec(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr)) - - // ========== 16-Bit ALU =========== - }, - 0x09: func() { - // ADD HL,BC - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.BC.HiLo()) - - }, - 0x19: func() { - // ADD HL,DE - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.DE.HiLo()) - - }, - 0x29: func() { - // ADD HL,HL - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.HL.HiLo()) - - }, - 0x39: func() { - // ADD HL,SP - gb.instAdd16(gb.CPU.HL.Set, gb.CPU.HL.HiLo(), gb.CPU.SP.HiLo()) - - }, - 0xE8: func() { - // ADD SP,n - gb.instAdd16Signed(gb.CPU.SP.Set, gb.CPU.SP.HiLo(), int8(gb.popPC())) - gb.CPU.SetZ(false) - - }, - 0x03: func() { - // INC BC - gb.instInc16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) - - }, - 0x13: func() { - // INC DE - gb.instInc16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) - - }, - 0x23: func() { - // INC HL - gb.instInc16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) - - }, - 0x33: func() { - // INC SP - gb.instInc16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) - - }, - 0x0B: func() { - // DEC BC - gb.instDec16(gb.CPU.BC.Set, gb.CPU.BC.HiLo()) - - }, - 0x1B: func() { - // DEC DE - gb.instDec16(gb.CPU.DE.Set, gb.CPU.DE.HiLo()) - - }, - 0x2B: func() { - // DEC HL - gb.instDec16(gb.CPU.HL.Set, gb.CPU.HL.HiLo()) - - }, - 0x3B: func() { - // DEC SP - gb.instDec16(gb.CPU.SP.Set, gb.CPU.SP.HiLo()) - - }, - 0x27: func() { /* - // DAA - When this instruction is executed, the A register is BCD - corrected using the contents of the flags. The exact process - is the following: if the least significant four bits of A - contain a non-BCD digit (i. e. it is greater than 9) or the - H flag is set, then $06 is added to the register. Then the - four most significant bits are checked. If this more significant - digit also happens to be greater than 9 or the C flag is set, - then $60 is added. - */ - if !gb.CPU.N() { - // TODO: This could be more efficient? - if gb.CPU.C() || gb.CPU.AF.Hi() > 0x99 { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x60) - gb.CPU.SetC(true) - } - if gb.CPU.H() || gb.CPU.AF.Hi()&0xF > 0x9 { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x06) - gb.CPU.SetH(false) - } - } else if gb.CPU.C() && gb.CPU.H() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0x9A) - gb.CPU.SetH(false) - } else if gb.CPU.C() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xA0) - } else if gb.CPU.H() { - gb.CPU.AF.SetHi(gb.CPU.AF.Hi() + 0xFA) - gb.CPU.SetH(false) - } - gb.CPU.SetZ(gb.CPU.AF.Hi() == 0) - - }, - 0x2F: func() { - // CPL - gb.CPU.AF.SetHi(0xFF ^ gb.CPU.AF.Hi()) - gb.CPU.SetN(true) - gb.CPU.SetH(true) - - }, - 0x3F: func() { - // CCF - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(!gb.CPU.C()) - - }, - 0x37: func() { - // SCF - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(true) - - }, - 0x00: func() { - // NOP - - }, - 0x76: func() { - // HALT - gb.halted = true - - }, - 0x10: func() { //gb.halted = true - // STOP - log.Print("0x10 (STOP) unimplemented (is 0x00 follows)") - - }, - 0xF3: func() { - // DI - gb.interruptsOn = false - - }, - 0xFB: func() { - // EI - gb.interruptsEnabling = true - - }, - 0x07: func() { - // RLCA - value := gb.CPU.AF.Hi() - result := byte(value<<1) | (value >> 7) - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(value > 0x7F) - - }, - 0x17: func() { - // RLA - value := gb.CPU.AF.Hi() - var carry byte - if gb.CPU.C() { - carry = 1 - } - result := byte(value<<1) + carry - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(value > 0x7F) - - }, - 0x0F: func() { - // RRCA - value := gb.CPU.AF.Hi() - result := byte(value>>1) | byte((value&1)<<7) - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC(result > 0x7F) - - }, - 0x1F: func() { - // RRA - value := gb.CPU.AF.Hi() - var carry byte - if gb.CPU.C() { - carry = 0x80 - } - result := byte(value>>1) | carry - gb.CPU.AF.SetHi(result) - gb.CPU.SetZ(false) - gb.CPU.SetN(false) - gb.CPU.SetH(false) - gb.CPU.SetC((1 & value) == 1) - - }, - 0xC3: func() { - // JP nn - gb.instJump(gb.popPC16()) - - }, - 0xC2: func() { - // JP NZ,nn - next := gb.popPC16() - if !gb.CPU.Z() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - }, - 0xCA: func() { - // JP Z,nn - next := gb.popPC16() - if gb.CPU.Z() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - }, - 0xD2: func() { - // JP NC,nn - next := gb.popPC16() - if !gb.CPU.C() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - }, - 0xDA: func() { - // JP C,nn - next := gb.popPC16() - if gb.CPU.C() { - gb.instJump(next) - gb.thisCpuTicks += 4 - } - - }, - 0xE9: func() { - // JP HL - gb.instJump(gb.CPU.HL.HiLo()) - - }, - 0x18: func() { - // JR n - addr := int32(gb.CPU.PC) + int32(int8(gb.popPC())) - gb.instJump(uint16(addr)) - - }, - 0x20: func() { - // JR NZ,n - next := int8(gb.popPC()) - if !gb.CPU.Z() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - }, - 0x28: func() { - // JR Z,n - next := int8(gb.popPC()) - if gb.CPU.Z() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - }, - 0x30: func() { - // JR NC,n - next := int8(gb.popPC()) - if !gb.CPU.C() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - }, - 0x38: func() { - // JR C,n - next := int8(gb.popPC()) - if gb.CPU.C() { - addr := int32(gb.CPU.PC) + int32(next) - gb.instJump(uint16(addr)) - gb.thisCpuTicks += 4 - } - - }, - 0xCD: func() { - // CALL nn - gb.instCall(gb.popPC16()) - - }, - 0xC4: func() { - // CALL NZ,nn - next := gb.popPC16() - if !gb.CPU.Z() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - }, - 0xCC: func() { - // CALL Z,nn - next := gb.popPC16() - if gb.CPU.Z() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - }, - 0xD4: func() { - // CALL NC,nn - next := gb.popPC16() - if !gb.CPU.C() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - }, - 0xDC: func() { - // CALL C,nn - next := gb.popPC16() - if gb.CPU.C() { - gb.instCall(next) - gb.thisCpuTicks += 12 - } - - }, - 0xC7: func() { - // RST 0x00 - gb.instCall(0x0000) - - }, - 0xCF: func() { - // RST 0x08 - gb.instCall(0x0008) - - }, - 0xD7: func() { - // RST 0x10 - gb.instCall(0x0010) - - }, - 0xDF: func() { - // RST 0x18 - gb.instCall(0x0018) - - }, - 0xE7: func() { - // RST 0x20 - gb.instCall(0x0020) - - }, - 0xEF: func() { - // RST 0x28 - gb.instCall(0x0028) - - }, - 0xF7: func() { - // RST 0x30 - gb.instCall(0x0030) - - }, - 0xFF: func() { - // RST 0x38 - gb.instCall(0x0038) - - }, - 0xC9: func() { - // RET - gb.instRet() - - }, - 0xC0: func() { - // RET NZ - if !gb.CPU.Z() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - }, - 0xC8: func() { - // RET Z - if gb.CPU.Z() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - }, - 0xD0: func() { - // RET NC - if !gb.CPU.C() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - }, - 0xD8: func() { - // RET C - if gb.CPU.C() { - gb.instRet() - gb.thisCpuTicks += 12 - } - - }, - 0xD9: func() { - // RETI - gb.instRet() - gb.interruptsEnabling = true - - }, - 0xCB: func() { - // CB - nextInst := gb.popPC() - gb.thisCpuTicks += CBOpcodeCycles[nextInst] * 4 - gb.cbInst[nextInst]() - }, - } - - // fill the empty elements of the array - // with a noop function to eliminate null checks - for k, v := range ret { - if v == nil { - opcode := k - ret[k] = func() { - log.Printf("Unimplemented opcode: %#2x", opcode) - WaitForInput() - } - } - } - - return ret -}