diff --git a/README.md b/README.md index 2bcfe15..246ecf0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ -# goboy -Gameboy emulator in go +# GoBoy +As an effort to improve my technical abilities and a challenge to myself +I've decided to start writing a GameBoy emulator in go. +This is the first time I've ever written an emulator \(outside of university +classes on FPGA emulation\). This is also my first project written in go. +I will be documenting everything in a series of blogs on my +[Personal Website](https://radu.macocian.me/GoBoy/) \ No newline at end of file diff --git a/cpu/cpu.go b/cpu/cpu.go new file mode 100644 index 0000000..9651473 --- /dev/null +++ b/cpu/cpu.go @@ -0,0 +1,29 @@ +package cpu + +import ( + "radu.macocian.me/goboy/memory" +) + +type cpu_struct struct { + A int8 + F int8 + B int8 + C int8 + D int8 + E int8 + H int8 + L int8 + IR int8 + IE int8 + + PC int16 + SP int16 +} + +var cpu = new(cpu_struct) + +func Execute(addr int) { + instr := memory.Read(addr + int(cpu.PC)) + cpu.PC++ + print(string(instr)) +} diff --git a/errorHandling/exceptions.go b/errorHandling/exceptions.go new file mode 100644 index 0000000..692d2ed --- /dev/null +++ b/errorHandling/exceptions.go @@ -0,0 +1,5 @@ +package errorHandling + +const InvalidRomError = "Critical Error. Invalid ROM file. Please make sure you input a valid .gb file. Exiting..." + +const OutOfMemoryBoundsError = "Critical Error. Trying to access data outside memory bounds. Exiting..." diff --git a/gameboy.go b/gameboy.go new file mode 100644 index 0000000..e1f6a58 --- /dev/null +++ b/gameboy.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "os" + "radu.macocian.me/goboy/cpu" + "radu.macocian.me/goboy/errorHandling" + "radu.macocian.me/goboy/memory" + "strings" +) + +func main() { + if len(os.Args) < 2 { + fmt.Println("Missing rom, please provide a rom") + return + } + + checkExtension(os.Args[1]) + + data, err := os.ReadFile(os.Args[1]) + check(err) + + startMem := 1000 + memory.WriteAll(startMem, data) + cpu.Execute(startMem) +} + +func checkExtension(file string) { + splits := strings.Split(file, ".") + if splits[len(splits)-1] != "gb" { + panic(errorHandling.InvalidRomError) + } +} + +func check(e error) { + if e != nil { + panic(e) + } +} diff --git a/journal/Day 1 - 2025.04.17.md b/journal/Day 1 - 2025.04.17.md new file mode 100644 index 0000000..f299047 --- /dev/null +++ b/journal/Day 1 - 2025.04.17.md @@ -0,0 +1,22 @@ +# First wrote a brief overview of the first milestone of the project: +- load files form the os +- create the memory struct with read/write functions on the memory +- create a cpu state with registers + +# For the day: +- Setup goland +- Disable autocomplete on space because it doesn't work +- Find ways to store memory state in go +- Write memory module with read, write, writeall functions +- Reading or writing outside of memory bounds will close app +- Write cpu module with registers, PC, SP +- Are registers only 8bits? +- Where are instructions stored? + +# Conclusion +- Can read roms from external files +- Have a 64kb memory with functions to read and write to it +- Have a cpu which reads instructions from the memory and increments the PC + +# References: +[Game Boy: Complete Technical Reference](https://gekkio.fi/files/gb-docs/gbctr.pdf) \ No newline at end of file diff --git a/journal/assets/day1.png b/journal/assets/day1.png new file mode 100644 index 0000000..76efab8 Binary files /dev/null and b/journal/assets/day1.png differ diff --git a/memory/memory.go b/memory/memory.go new file mode 100644 index 0000000..402c6db --- /dev/null +++ b/memory/memory.go @@ -0,0 +1,35 @@ +package memory + +import ( + "radu.macocian.me/goboy/errorHandling" +) + +var memory = new([64000]byte) + +func Read(addr int) []byte { + checkInside(addr) + checkInside(addr + 8) + + return memory[addr : addr+9] +} + +func Write(addr int, val [8]byte) { + checkInside(addr) + for i := 0; i < 8; i++ { + memory[addr+i] = val[i] + } +} + +func WriteAll(addr int, val []byte) { + checkInside(addr) + checkInside(addr + len(val)) + for b := 0; b < len(val); b++ { + memory[addr+b] = val[b] + } +} + +func checkInside(addr int) { + if addr < 0 || addr >= len(memory) { + panic(errorHandling.OutOfMemoryBoundsError) + } +} diff --git a/roms/rom.gb b/roms/rom.gb new file mode 100644 index 0000000..5308e77 --- /dev/null +++ b/roms/rom.gb @@ -0,0 +1 @@ +noop \ No newline at end of file