From 0f4a97bbf298b221a0e1a524071ecd4ebdc9e377 Mon Sep 17 00:00:00 2001 From: radumacocian Date: Mon, 30 Jun 2025 15:58:53 +0200 Subject: [PATCH] finished first row of opcodes --- cpu/flags.go | 22 +++++++++- cpu/functions.go | 75 +++++++++++++++++++++++------------ cpu/operations/shift.go | 6 ++- cpu/operations/shift_test.go | 16 +++++++- cpu/optable.go | 10 ++++- journal/Day 3 - 2025.06.30.md | 7 ++++ 6 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 journal/Day 3 - 2025.06.30.md diff --git a/cpu/flags.go b/cpu/flags.go index de184c6..6d7430b 100644 --- a/cpu/flags.go +++ b/cpu/flags.go @@ -1,6 +1,10 @@ package cpu -func Set8BitAddFlags(context op_context, byte1 byte, byte2 byte) byte { +import ( + "radu.macocian.me/goboy/cpu/operations" +) + +func Add8BitsAndSetFlags(context op_context, byte1 byte, byte2 byte) byte { result := uint16(byte1) + uint16(byte2) halfcarry := (byte1&0x0F)+(byte2&0x0F) > 0x0F context.cpu.SetNF(false) @@ -17,3 +21,19 @@ func Add16BitsAndSetFlags(context op_context, op1 uint16, op2 uint16) uint16 { context.cpu.SetCF(result > 0xFFFF) return uint16(result) } + +func IncAndSetFlags(context op_context, op1 *byte) { + halfcarry := *op1&0x0F == 0x0F + context.cpu.SetNF(false) + context.cpu.SetHF(halfcarry) + context.cpu.SetZF(*op1 == byte(0)) + operations.INC(op1) +} + +func DecAndSetFlags(context op_context, op1 *byte) { + halfcarry := *op1&0x0F == 0x00 + context.cpu.SetZF(*op1 == byte(0)) + context.cpu.SetNF(true) + context.cpu.SetHF(halfcarry) + operations.DEC(op1) +} diff --git a/cpu/functions.go b/cpu/functions.go index 162d5bb..02e9294 100644 --- a/cpu/functions.go +++ b/cpu/functions.go @@ -34,48 +34,33 @@ func INCBC(context op_context) { // 0x04 INCB Increment the contents of register B by 1. func INCB(context op_context) { - if context.cpu.B&0x0F == 0x0F { - context.cpu.SetHF(true) - } else { - context.cpu.SetHF(false) - } - operations.INC(&context.cpu.B) - - context.cpu.SetZF(context.cpu.B == byte(0)) - context.cpu.SetNF(false) + IncAndSetFlags(context, &context.cpu.B) } // 0x05 DECB Decrement the contents of register B by 1. func DECB(context op_context) { - if context.cpu.B&0x0F == 0x00 { - context.cpu.SetHF(true) - } else { - context.cpu.SetHF(false) - } - operations.DEC(&context.cpu.B) - - context.cpu.SetZF(context.cpu.B == byte(0)) - context.cpu.SetNF(true) + DecAndSetFlags(context, &context.cpu.B) } -// 0x06 LD8B Load the 8-bit immediate operand d8 into register B. -func LD8B(context op_context) { - operations.LD(&context.cpu.B, memory.Read8(uint(context.immediate))) +// 0x06 LDBd8 Load the 8-bit immediate operand d8 into register B. +func LDBd8(context op_context) { + operations.LD(&context.cpu.B, byte(context.immediate)) } // 0x07 RLCA Rotate the contents of register A to the left. The contents of bit 7 are placed in both the CY flag and bit 0 of register A. func RLCA(context op_context) { - a7 := context.cpu.A>>7 == 1 - operations.Shift(&context.cpu.A) + a7 := context.cpu.A >> 7 + operations.ShiftLeft(&context.cpu.A) + context.cpu.A = context.cpu.A | byte(a7) context.cpu.SetZF(false) context.cpu.SetNF(false) context.cpu.SetHF(false) - context.cpu.SetCF(a7) + context.cpu.SetCF(a7 == 1) } -// 0x08 LDA16 Store the lower byte of stack pointer SP at the address specified by the 16-bit immediate operand a16, and store the upper byte of SP at address a16 + 1. -func LDA16(context op_context) { +// 0x08 LDa16SP Store the lower byte of stack pointer SP at the address specified by the 16-bit immediate operand a16, and store the upper byte of SP at address a16 + 1. +func LDa16SP(context op_context) { operations.LDInMemory8(context.immediate, operations.GetLowerByte(context.cpu.SP)) operations.LDInMemory8(context.immediate+1, operations.GetHigherByte(context.cpu.SP)) } @@ -85,3 +70,41 @@ func ADDHLBC(context op_context) { result := Add16BitsAndSetFlags(context, context.cpu.HL(), context.cpu.BC()) context.cpu.SetHL(result) } + +// 0x0A LDABC Load the 8-bit contents of memory specified by register pair BC into register A. +func LDABC(context op_context) { + operations.LDFromMem(&context.cpu.A, uint(context.cpu.BC())) +} + +// 0x0B DECBC Decrement the contents of register pair BC by 1. +func DECBC(context op_context) { + operations.DEC16(&context.cpu.B, &context.cpu.C) +} + +// 0x0C INCC Increment the contents of register C by 1. +func INCC(context op_context) { + IncAndSetFlags(context, &context.cpu.C) +} + +// 0x0D DECC Decrement the contents of register C by 1. +func DECC(context op_context) { + DecAndSetFlags(context, &context.cpu.C) +} + +// 0x0E LDCd8 Load the 8-bit immediate operand d8 into register C. +func LDCd8(context op_context) { + context.cpu.C = byte(context.immediate) +} + +// 0x0F RRRCA Rotate the contents of register A to the right. That is, the contents of bit 7 are copied to bit 6, and the previous contents of bit 6 (before the copy) are copied to bit 5. The same operation is repeated in sequence for the rest of the register. The contents of bit 0 are placed in both the CY flag and bit 7 of register A. +func RRRCA(context op_context) { + a0 := context.cpu.A & 0x01 + operations.ShiftRight(&context.cpu.A) + context.cpu.A = context.cpu.A | byte(a0)<<7 + + context.cpu.SetZF(false) + context.cpu.SetNF(false) + context.cpu.SetHF(false) + context.cpu.SetCF(a0 == 1) + +} diff --git a/cpu/operations/shift.go b/cpu/operations/shift.go index c68259a..3e71ba9 100644 --- a/cpu/operations/shift.go +++ b/cpu/operations/shift.go @@ -1,5 +1,9 @@ package operations -func Shift(r1 *byte) { +func ShiftLeft(r1 *byte) { *r1 = *r1 << 1 } + +func ShiftRight(r1 *byte) { + *r1 = *r1 >> 1 +} diff --git a/cpu/operations/shift_test.go b/cpu/operations/shift_test.go index 5073b69..17d0164 100644 --- a/cpu/operations/shift_test.go +++ b/cpu/operations/shift_test.go @@ -4,9 +4,9 @@ import ( "testing" ) -func TestShift(t *testing.T) { +func TestShiftLeft(t *testing.T) { r1 := byte(0b01010101) - Shift(&r1) + ShiftLeft(&r1) expected := byte(0b10101010) actual := r1 @@ -15,3 +15,15 @@ func TestShift(t *testing.T) { t.Errorf("actual %x != expected %x", actual, expected) } } + +func TestShiftRight(t *testing.T) { + r1 := byte(0b01010101) + ShiftLeft(&r1) + + expected := byte(0b00101010) + actual := r1 + + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} diff --git a/cpu/optable.go b/cpu/optable.go index 2936bd7..21c9d51 100644 --- a/cpu/optable.go +++ b/cpu/optable.go @@ -7,6 +7,14 @@ var OpTable = [256]func(context op_context){ INCBC, //0x03 INCB, //0x04 DECB, //0x05 - LD8B, //0x06 + LDBd8, //0x06 RLCA, //0x07 + LDa16SP, //0x08 + ADDHLBC, //0x09 + LDABC, //0x0A + DECBC, //0x0B + INCC, //0x0C + DECC, //0x0D + LDCd8, //0x0E + RRRCA, //0x0F } diff --git a/journal/Day 3 - 2025.06.30.md b/journal/Day 3 - 2025.06.30.md new file mode 100644 index 0000000..1029d44 --- /dev/null +++ b/journal/Day 3 - 2025.06.30.md @@ -0,0 +1,7 @@ +# For the day: +- Understand the cpu flags and when they are set + +# Conclusion +- Wrote helper functions for setting the flags after addition/subtraction +- Understood when the half-carry flag is set in addtions and subtractions +- ?The carry flag is not set of INC and DEC operations?