diff --git a/Makeconf b/Makeconf new file mode 100644 index 0000000..0e0571e --- /dev/null +++ b/Makeconf @@ -0,0 +1,5 @@ +modules := test \ + memory/bus \ + memory/ram + +CXX_FLAGS := -I $(CURDIR) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4ce61c1 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +include Makeconf + +$(info $(modules)) +objs := $(addsuffix .o,$(modules)) + +%.o: %.cpp + g++ $(CXX_FLAGS) -c -o $@ $^ + +vgbc: $(objs) + g++ -o $@ $^ diff --git a/cpu/cpu.h b/cpu/cpu.h new file mode 100644 index 0000000..81858cc --- /dev/null +++ b/cpu/cpu.h @@ -0,0 +1,62 @@ +#pragma once + +#include "types.h" + +class Cpu; +class Mem_device; + +enum Flags { + F_ZERO = 0x8, + F_SUB = 0x4, + F_HALF = 0x2, + F_CARRY = 0x1, +}; + +union Register_pair { + struct { u8 hi; u8 lo; } + u16 hilo; +}; + +struct Cpu_state { + // Registers + union { + u16 BC; + struct { u8 B; u8 C; }; + }; + union { + u16 DE; + struct { u8 D; u8 E; }; + }; + union { + u16 HL; + struct { u8 H; u8 L; }; + }; + + u8 A; + u16 SP; + u16 PC; + + bool zero; + bool subtract; + bool halfcarry; + bool carry; +}; + +class Cpu { +private: + Cpu_state state; + Mem_device* bus; + + typedef u8 opcode_t; + +private: + u8 readPC(); + + void pushStack(u8 data); + u8 popStack(); + +public: + Cpu(); + + void step(); +}; diff --git a/cpu/decoder.cpp b/cpu/decoder.cpp new file mode 100644 index 0000000..0161dbd --- /dev/null +++ b/cpu/decoder.cpp @@ -0,0 +1,108 @@ +#include "cpu/cpu.h" + +u8 Cpu::readPC8() +{ + u8 data = bus->read8(state.PC); + state.PC++; + return data; +} + +u16 Cpu::readPC16() +{ + u16 data = bus->read16(state.PC); + state.PC+=2; + return data; +} + +void pushStack8(u8 data) +{ + bus->write8(state.SP, data); + state.SP--; +} + +u8 popStack8() +{ + u8 data = bus->read8(state.SP); + state.SP++; + return data; +} + +void pushStack16(u16 data) +{ + bus->write16(state.SP,data); + state.SP-=2; +} + +void popStack16() +{ + u16 data = bus->read16(state.SP); + state.SP+=2; + return data; +} + +void Cpu::step() +{ + opcode_t op = readPC(); + int mcycles = 1; + switch(op) { + 0x00: // NOP + (void) ;; + + 0x01: // LD BC, n16 + state.BC = readPC16(); mcycles = 12;; + 0x11: // LD DE, n16 + state.DE = readPC16(); mcycles = 12;; + 0x21: // LD HL, n16 + state.HL = readPC16(); mcycles = 12;; + 0x31: // LD SP, n16 + state.SP = readPC16(); mcycles = 12;; + + 0x02: // LD [BC], A + bus->write8(state.BC, state.A); mcycles = 8;; + 0x12: // LD [DE], A + bus->write8(state.DE, state.A); mcycles = 8;; + 0x22: // LD [HL+], A + bus->write8(state.HL, state.A); state.HL++; mcycles = 8;; + 0x32: // LD [HL-], A + bus->write8(state.HL, state.A); state.HL--; mcycles = 8;; + + 0x03: // INC BC + state.BC++; mcycles = 2;; + 0x13: // INC DE + state.DE++; mcycles = 2;; + 0x23: // INC HL + state.HL++; mcycles = 2;; + 0x33: // INC SP + state.SP++; mcycles = 2;; + + 0x04: // INC B + state.B++; + state.zero = (state.B == 0); + state.subtract = false; + state.halfcarry = (state.B & 0x0F == 0); + ; + 0x14: // INC D + state.D++; + state.zero = (state.D == 0); + state.subtract = false; + state.halfcarry = (state.D & 0x0F == 0); + ; + 0x24: // INC H + state.H++; + state.zero = (state.H == 0); + state.subtract = false; + state.halfcarry = (state.H & 0x0F == 0); + ; + 0x34: // INC [HL] + u8 data = bus->read8(state.HL); + data++; + bus->write8(state.HL, data); + state.zero = (data == 0); + state.subtract = false; + state.halfcarry = (data & 0x0F == 0); + mcycles = 3; + ; + + + } +} diff --git a/memory/bus.cpp b/memory/bus.cpp new file mode 100644 index 0000000..50d1033 --- /dev/null +++ b/memory/bus.cpp @@ -0,0 +1,51 @@ +#include "bus.h" + +Bus::Bus() : map() {} + +std::optional Bus::find_entry(u16 addr) +{ + for(auto it = map.begin(); it != map.end(); ++it) + { + if (addr >= it->start && addr <= it->end) + return std::make_optional(*it); + } + + return {}; +} + +void Bus::map_device(u16 start, u16 end, Mem_device* dev) +{ + map.push_back(Bus::MapEntry{ start, end, dev }); +} + +void Bus::write8(u16 addr, u8 data) +{ + auto mapentry = find_entry(addr); + + if(!mapentry) return; + + mapentry->dev->write8(addr - mapentry->start, data); +} + +u8 Bus::read8(u16 addr) +{ + auto mapentry = find_entry(addr); + + if(!mapentry) return 0xFFu; + + return mapentry->dev->read8(addr - mapentry->start); +} + +void Bus::write16(u16 addr, u16 data) +{ + auto mapentry = find_entry(addr); + if(!mapentry) return; + mapentry->dev->write16(addr - mapentry->start, data); +} + +u16 Bus::read16(u16 addr) +{ + auto mapentry = find_entry(addr); + if(!mapentry) return 0xFFFFu; + return mapentry->dev->read16(addr - mapentry->start); +} diff --git a/memory/bus.h b/memory/bus.h new file mode 100644 index 0000000..2581d4b --- /dev/null +++ b/memory/bus.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "mem_device.h" + +class Bus : public Mem_device { +private: + struct MapEntry { + u16 start; + u16 end; + Mem_device *dev; + }; + + std::optional find_entry(u16 addr); + +public: + Bus(); + + void map_device(u16 start, u16 end, Mem_device* dev); + + virtual void write8(u16 addr, u8 data); + virtual u8 read8(u16 addr); + + virtual void write16(u16 addr, u16 data); + virtual u16 read16(u16 addr); + +private: + std::vector map; +}; diff --git a/memory/mem_device.h b/memory/mem_device.h new file mode 100644 index 0000000..039d3a3 --- /dev/null +++ b/memory/mem_device.h @@ -0,0 +1,12 @@ +#pragma once + +#include "types.h" + +class Mem_device { +public: + virtual void write8(u16 addr, u8 data) = 0; + virtual u8 read8(u16 addr) = 0; + + virtual void write16(u16 addr, u16 data) = 0; + virtual u16 read16(u16 addr) = 0; +}; diff --git a/memory/ram.cpp b/memory/ram.cpp new file mode 100644 index 0000000..3c445a5 --- /dev/null +++ b/memory/ram.cpp @@ -0,0 +1,31 @@ +#include "ram.h" + +RAM::RAM(u16 size) : size(size), readonly(false) { + memory = new u8[size]; +} + +RAM::RAM(u8* memory, u16 size, bool readonly = false) + : memory(memory), size(size), readonly(readonly) +{} + +void RAM::write8(u16 addr, u8 data) { + if(addr >= size || readonly) return; + memory[addr] = data; +} + +u8 RAM::read8(u16 addr) { + if (addr >= size) return 0xFFu; + return memory[addr]; +} + +void RAM::write16(u16 addr, u16 data) { + if(addr >= size - 1 || readonly) return; + u16 *ptr = (u16*)&memory[addr]; + *ptr = data; +} + +u16 RAM::read16(u16 addr) { + if(addr >= size - 1) return; + u16 *ptr = (u16*)&memory[addr]; + return *ptr; +} diff --git a/memory/ram.h b/memory/ram.h new file mode 100644 index 0000000..b16ad18 --- /dev/null +++ b/memory/ram.h @@ -0,0 +1,20 @@ +#pragma once + +#include "mem_device.h" + +class RAM : public Mem_device { +private: + u8* memory; + u16 size; + bool readonly; + +public: + RAM(u16 size); + RAM(u8* memory, u16 size, bool readonly = false); + + virtual void write8(u16 addr, u8 data); + virtual u8 read8(u16 addr); + + virtual void write16(u16 addr, u16 data); + virtual u16 read16(u16 addr); +}; diff --git a/types.h b/types.h new file mode 100644 index 0000000..0ed4a10 --- /dev/null +++ b/types.h @@ -0,0 +1,7 @@ +#pragma once + +typedef unsigned char u8; +typedef unsigned short u16; + +typedef signed char s8; +typedef signed short s16;