diff --git a/cpu/functions.go b/cpu/functions.go new file mode 100644 index 0000000..918e919 --- /dev/null +++ b/cpu/functions.go @@ -0,0 +1,48 @@ +package cpu + +import ( + "radu.macocian.me/goboy/cpu/operations" + "radu.macocian.me/goboy/memory" +) + +type op_context struct { + cpu CPU_struct + addr uint +} + +func Noop(context op_context) { + return +} + +// LDBCd16 Load the 2 bytes of immediate data into register pair BC. +func LDBCd16(context op_context) { + operations.LD(&context.cpu.C, memory.Read8(context.addr)) + operations.LD(&context.cpu.B, memory.Read8(context.addr+8)) +} + +// LDBCa Store the contents of register A in the memory location specified by register pair BC. +func LDBCa(context op_context) { + operations.LDInMemory8(context.cpu.BC(), context.cpu.A) + return +} + +// INCBC Increment the contents of register pair BC by 1. +func INCBC(context op_context) { + operations.INC16(&context.cpu.B, &context.cpu.C) + return +} + +// INCB Increment the contents of register B by 1. +func INCB(context op_context) { + operations.INC(&context.cpu.B) +} + +// DECB Decrement the contents of register B by 1. +func DECB(context op_context) { + operations.DEC(&context.cpu.B) +} + +// LD8B Load the 8-bit immediate operand d8 into register B. +func LD8B(context op_context) { + operations.LD(&context.cpu.B, memory.Read8(context.addr)) +} diff --git a/cpu/operations/add.go b/cpu/operations/add.go new file mode 100644 index 0000000..a64a218 --- /dev/null +++ b/cpu/operations/add.go @@ -0,0 +1,11 @@ +package operations + +import "radu.macocian.me/goboy/memory" + +func ADD(r1 *byte, r2 *byte) { + *r1 += *r2 +} + +func ADDFromMem(r1 *byte, r2 uint) { + *r1 += memory.Read8(r2) +} diff --git a/cpu/operations/add_test.go b/cpu/operations/add_test.go new file mode 100644 index 0000000..bd5171d --- /dev/null +++ b/cpu/operations/add_test.go @@ -0,0 +1,33 @@ +package operations + +import ( + "radu.macocian.me/goboy/memory" + "testing" +) + +func TestADD(t *testing.T) { + r1 := byte(3) + r2 := byte(4) + ADD(&r1, &r2) + + expected := byte(7) + actual := r1 + + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} + +func TestADDFromMem(t *testing.T) { + r1 := byte(3) + addr := uint(1000) + memory.Write8(addr, byte(6)) + ADDFromMem(&r1, addr) + + expected := byte(9) + actual := r1 + + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} diff --git a/cpu/operations/dec.go b/cpu/operations/dec.go new file mode 100644 index 0000000..5271731 --- /dev/null +++ b/cpu/operations/dec.go @@ -0,0 +1,14 @@ +package operations + +func DEC(r1 *byte) { + *r1-- +} + +func DEC16(r1 *byte, r2 *byte) { + if *r2 == 0x00 { + *r2 = 0xFF + *r1-- + return + } + *r2-- +} diff --git a/cpu/operations/dec_test.go b/cpu/operations/dec_test.go new file mode 100644 index 0000000..c3f527c --- /dev/null +++ b/cpu/operations/dec_test.go @@ -0,0 +1,37 @@ +package operations + +import "testing" + +func TestDEC(t *testing.T) { + r1 := byte(3) + DEC(&r1) + + expected := byte(2) + actual := r1 + + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} + +func TestDEC16(t *testing.T) { + r1 := byte(0xAB) + r2 := byte(0x11) + DEC16(&r1, &r2) + + expected := uint16(0xAB10) + actual := (uint16(r1) << 8) | uint16(r2) + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } + + r1 = byte(0x11) + r2 = byte(0x00) + DEC16(&r1, &r2) + + expected = uint16(0x1000) + actual = (uint16(r1) << 8) | uint16(r2) + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} diff --git a/cpu/operations/inc.go b/cpu/operations/inc.go new file mode 100644 index 0000000..3942197 --- /dev/null +++ b/cpu/operations/inc.go @@ -0,0 +1,14 @@ +package operations + +func INC(r1 *byte) { + *r1++ +} + +func INC16(r1 *byte, r2 *byte) { + if *r2 == 0xFF { + *r2 = 0 + *r1++ + return + } + *r2++ +} diff --git a/cpu/operations/inc_test.go b/cpu/operations/inc_test.go new file mode 100644 index 0000000..2cec6cd --- /dev/null +++ b/cpu/operations/inc_test.go @@ -0,0 +1,39 @@ +package operations + +import ( + "testing" +) + +func TestINC(t *testing.T) { + r1 := byte(3) + INC(&r1) + + expected := byte(4) + actual := r1 + + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} + +func TestINC16(t *testing.T) { + r1 := byte(0xAB) + r2 := byte(0x11) + INC16(&r1, &r2) + + expected := uint16(0xAB12) + actual := (uint16(r1) << 8) | uint16(r2) + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } + + r1 = byte(0x11) + r2 = byte(0xFF) + INC16(&r1, &r2) + + expected = uint16(0x1200) + actual = (uint16(r1) << 8) | uint16(r2) + if actual != expected { + t.Errorf("actual %x != expected %x", actual, expected) + } +} diff --git a/cpu/operations/load.go b/cpu/operations/load.go new file mode 100644 index 0000000..5e8534d --- /dev/null +++ b/cpu/operations/load.go @@ -0,0 +1,15 @@ +package operations + +import "radu.macocian.me/goboy/memory" + +func LD(r1 *byte, val byte) { + *r1 = val +} + +func LDFromMem(r1 *byte, r2 uint) { + *r1 = memory.Read8(r2) +} + +func LDInMemory8(addr uint16, val byte) { + memory.Write8(uint(addr), val) +} diff --git a/cpu/optable.go b/cpu/optable.go new file mode 100644 index 0000000..7891aa6 --- /dev/null +++ b/cpu/optable.go @@ -0,0 +1,16 @@ +package cpu + +type operation func(byte) + +var OpTable = [256]func(context op_context){ + Noop, //0x00 + LDBCd16, //0x01 + LDBCa, //0x02 + INCBC, //0x03 + INCB, //0x04 + DECB, //0x05 + LD8B, //0x06 +} + +func (cpu *CPU_struct) execute(op byte, addr uint) { +} diff --git a/gameboy.go b/gameboy.go index e1f6a58..3957f75 100644 --- a/gameboy.go +++ b/gameboy.go @@ -20,7 +20,7 @@ func main() { data, err := os.ReadFile(os.Args[1]) check(err) - startMem := 1000 + startMem := uint(1000) memory.WriteAll(startMem, data) cpu.Execute(startMem) } diff --git a/memory/memory.go b/memory/memory.go index c8c2fa4..0e507cf 100644 --- a/memory/memory.go +++ b/memory/memory.go @@ -13,6 +13,19 @@ func Read(addr uint) []byte { return memory[addr : addr+9] } +func Read8(addr uint) byte { + checkInside(addr) + + return memory[addr] +} + +func Read16(addr uint) uint16 { + checkInside(addr) + checkInside(addr + 8) + + return uint16(memory[addr])<<8 | uint16(memory[addr+1]) +} + func Write(addr uint, val [8]byte) { checkInside(addr) for i := 0; i < 8; i++ { @@ -20,6 +33,11 @@ func Write(addr uint, val [8]byte) { } } +func Write8(addr uint, val byte) { + checkInside(addr) + memory[int(addr)] = val +} + func WriteAll(addr uint, val []byte) { checkInside(addr) checkInside(addr + uint(len(val)))