From bc3a0ff63aa72c37d4c731a7ce1e9cef306d66dd Mon Sep 17 00:00:00 2001 From: CocoSimone Date: Mon, 16 May 2022 09:29:55 +0200 Subject: [PATCH] more memory work --- src/core/common.hpp | 5 ++- src/core/gb/CMakeLists.txt | 8 +++- src/core/gb/Core.cpp | 8 +++- src/core/gb/Core.hpp | 2 + src/core/gb/Cpu.cpp | 14 +++++- src/core/gb/Cpu.hpp | 7 ++- src/core/gb/Mem.cpp | 81 ++++++++++++++++++++++++++++++++++ src/core/gb/Mem.hpp | 30 +++++++++++++ src/core/gb/mbc.cpp | 24 ++++++++++ src/core/gb/mbc.hpp | 23 ++++++++++ src/core/gb/memory_regions.hpp | 34 ++++++++++++++ src/core/util.hpp | 7 +++ src/frontend/sdl/Frontend.cpp | 8 ++-- 13 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 src/core/gb/Mem.cpp create mode 100644 src/core/gb/Mem.hpp create mode 100644 src/core/gb/mbc.cpp create mode 100644 src/core/gb/mbc.hpp create mode 100644 src/core/gb/memory_regions.hpp diff --git a/src/core/common.hpp b/src/core/common.hpp index 9ca6b53d..408ad63b 100644 --- a/src/core/common.hpp +++ b/src/core/common.hpp @@ -2,6 +2,7 @@ #include #include #include +#include using u8 = uint8_t; using u16 = uint16_t; @@ -19,4 +20,6 @@ using m128 = __m128i; #define UINT128_MIN 0 #define INT128_MAX ((u128)0x7FFF'FFFF'FFFF'FFFF << 64) | 0xFFFF'FFFF'FFFF'FFFF #define INT128_MIN (-INT128_MAX - 1LL) - +#define KiB * 1024 +#define MiB (KiB * 1024) +#define GiB (MiB * 1024) diff --git a/src/core/gb/CMakeLists.txt b/src/core/gb/CMakeLists.txt index 48577f07..38a67b04 100644 --- a/src/core/gb/CMakeLists.txt +++ b/src/core/gb/CMakeLists.txt @@ -3,5 +3,9 @@ project(gb CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_library(gb Core.hpp Core.cpp Cpu.hpp Cpu.cpp Ppu.hpp Ppu.cpp) -target_include_directories(gb PUBLIC .) +find_package(mio REQUIRED) +find_package(fmt REQUIRED) + +add_library(gb Core.hpp Core.cpp Cpu.hpp Cpu.cpp Ppu.hpp Ppu.cpp Mem.cpp Mem.hpp mbc.cpp mbc.hpp memory_regions.hpp) +target_include_directories(gb PUBLIC . ..) +target_link_libraries(gb PUBLIC mio::mio fmt::fmt) diff --git a/src/core/gb/Core.cpp b/src/core/gb/Core.cpp index 3bf765be..b62a2ef8 100644 --- a/src/core/gb/Core.cpp +++ b/src/core/gb/Core.cpp @@ -2,4 +2,10 @@ namespace natsukashii::core { Core::Core() {} -} \ No newline at end of file + +void Core::Run() { + while(true) { + cpu.Step(mem); + } +} +} diff --git a/src/core/gb/Core.hpp b/src/core/gb/Core.hpp index 728dee25..7e9a23f3 100644 --- a/src/core/gb/Core.hpp +++ b/src/core/gb/Core.hpp @@ -1,12 +1,14 @@ #pragma once #include "Cpu.hpp" #include "Ppu.hpp" +#include "Mem.hpp" namespace natsukashii::core { struct Core { Core(); void Run(); private: + Mem mem; Cpu cpu; // Ppu ppu; }; diff --git a/src/core/gb/Cpu.cpp b/src/core/gb/Cpu.cpp index d4f4df7f..81ffb218 100644 --- a/src/core/gb/Cpu.cpp +++ b/src/core/gb/Cpu.cpp @@ -1,6 +1,18 @@ #include +#include namespace natsukashii::core { Cpu::Cpu() { } -} \ No newline at end of file + +void Cpu::Step(Mem& mem) { + u8 opcode = mem.Consume(pc); + DecodeAndExecute(opcode); +} + +void Cpu::DecodeAndExecute(u8 opcode) { + switch(opcode) { + default: util::panic("Unimplemented opcode %02X", opcode); + } +} +} diff --git a/src/core/gb/Cpu.hpp b/src/core/gb/Cpu.hpp index c57bc52c..ccab9ab6 100644 --- a/src/core/gb/Cpu.hpp +++ b/src/core/gb/Cpu.hpp @@ -1,11 +1,13 @@ #pragma once -#include "../common.hpp" +#include "Mem.hpp" namespace natsukashii::core { #define af regs.AF #define bc regs.BC #define de regs.DE #define hl regs.HL +#define pc regs.PC +#define sp regs.SP #define a af.A #define f af.F @@ -76,11 +78,14 @@ struct Registers { REGIMPL(u8, B, u8, C); REGIMPL(u8, C, u8, E); REGIMPL(u8, D, u8, L); + u16 PC = 0, SP = 0; }; struct Cpu { Cpu(); + void Step(Mem&); private: + void DecodeAndExecute(u8); Registers regs; }; } diff --git a/src/core/gb/Mem.cpp b/src/core/gb/Mem.cpp new file mode 100644 index 00000000..37dd5464 --- /dev/null +++ b/src/core/gb/Mem.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +namespace natsukashii::core { +template +T ReadCart(const std::unique_ptr& cart, u16 addr) { + if constexpr(sizeof(T) == 1) return cart->Read8(addr); + else if constexpr(sizeof(T) == 2) return cart->Read16(addr); + else if constexpr(sizeof(T) == 4) return cart->Read32(addr); +} + +template +void WriteCart(const std::unique_ptr& cart, u16 addr, T val) { + if constexpr(sizeof(T) == 1) cart->Write8(addr, val); + else if constexpr(sizeof(T) == 2) cart->Write16(addr, val); + else if constexpr(sizeof(T) == 4) cart->Write32(addr, val); +} + +void Mem::LoadROM(const std::string& filename) { + std::ifstream file(filename, std::ios::binary); + file.unsetf(std::ios::skipws); + + if(!file.is_open()) { + util::panic("Unable to open {}!", filename); + } + + file.seekg(std::ios::end); + auto size = file.tellg(); + file.seekg(std::ios::beg); + + std::vector rom; + rom.reserve(size); + rom.insert(rom.begin(), + std::istream_iterator(file), + std::istream_iterator()); + + file.close(); + + cart = std::make_unique(rom); +} + +template +T Mem::Read(u16 addr) { + switch(addr) { + case ROM_RNG00: return io.BootROMMapped() ? bootrom[addr] : ReadCart(cart, addr); + case ROM_RNGNN: return ReadCart(cart, addr); + default: util::panic("[READ] Unimplemented addr: {:04X}", addr); + } + + return 0; +} + +template u8 Mem::Read(u16); +template u16 Mem::Read(u16); +template u32 Mem::Read(u16); + +template +void Mem::Write(u16 addr, T val) { + switch(addr) { + case ROM_RNG00: case ROM_RNGNN: WriteCart(cart, addr, val); + default: util::panic("[WRITE] Unimplemented addr: {:04X}", addr); + } +} + +template void Mem::Write(u16, u8); +template void Mem::Write(u16, u16); +template void Mem::Write(u16, u32); + +template +T Mem::Consume(u16& pc) { + T result = Read(pc); + pc += sizeof(T); + return result; +} + +template u8 Mem::Consume(u16&); +template u16 Mem::Consume(u16&); +template u32 Mem::Consume(u16&); +} diff --git a/src/core/gb/Mem.hpp b/src/core/gb/Mem.hpp new file mode 100644 index 00000000..95b6d0ec --- /dev/null +++ b/src/core/gb/Mem.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace natsukashii::core { +struct IO { + [[nodiscard]] bool BootROMMapped() const { return ff50 != 1; } +private: + u8 ff50 = 0; +}; + +struct Mem { + Mem() = default; + void LoadROM(const std::string& filename); + template + T Read(u16 addr); + template + void Write(u16 addr, T val); + template + T Consume(u16& pc); +private: + std::unique_ptr cart; + IO io{}; + u8 bootrom[BOOTROM_SIZE]{}; +}; +} diff --git a/src/core/gb/mbc.cpp b/src/core/gb/mbc.cpp new file mode 100644 index 00000000..f3a4dc75 --- /dev/null +++ b/src/core/gb/mbc.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +namespace natsukashii::core { +NoMBC::NoMBC(std::vector rom) : data(std::move(rom)) {} + +u8 NoMBC::Read8(u16 addr) { + return data[addr]; +} + +void NoMBC::Write8(u16 addr, u8 val) { + util::panic("Writing to a NoMBC cartridge is not allowed!"); +} + +u16 NoMBC::Read16(u16 addr) { + return ((u16)Read8(addr) << 8) | Read8(addr + 1); +} + +void NoMBC::Write16(u16 addr, u16 val) { + Write8(addr, val >> 8); + Write8(addr + 1, val & 0xff); +} +} \ No newline at end of file diff --git a/src/core/gb/mbc.hpp b/src/core/gb/mbc.hpp new file mode 100644 index 00000000..e06d1d16 --- /dev/null +++ b/src/core/gb/mbc.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include + +namespace natsukashii::core { +struct Cartridge { + virtual u8 Read8(u16 addr); + virtual u16 Read16(u16 addr); + virtual void Write8(u16 addr, u8 val); + virtual void Write16(u16 addr, u16 val); +}; + +struct NoMBC : public Cartridge { + explicit NoMBC(std::vector rom); + u8 Read8(u16 addr) override; + void Write8(u16 addr, u8 val) override; + u16 Read16(u16 addr) override; + void Write16(u16 addr, u16 val) override; +private: + std::vector data{}; +}; +} \ No newline at end of file diff --git a/src/core/gb/memory_regions.hpp b/src/core/gb/memory_regions.hpp new file mode 100644 index 00000000..580a25cf --- /dev/null +++ b/src/core/gb/memory_regions.hpp @@ -0,0 +1,34 @@ +#pragma once +#include + +#define BOOTROM_SIZE 512 +#define ROM_STR00 0x0000 +#define ROM_END00 ROM_STR00 + 16 KiB - 1 +#define ROM_STRNN ROM_END00 + 1 +#define ROM_ENDNN ROM_STRNN + 16 KiB - 1 +#define ROM_RNG00 ROM_STR00 ... ROM_END00 +#define ROM_RNGNN ROM_STRNN ... ROM_ENDNN +#define VRAM_START ROM_ENDNN + 1 +#define VRAM_END VRAM_START + 8 KiB - 1 +#define VRAM_RANGE VRAM_START ... VRAM_END +#define EXTRAM_START VRAM_END + 1 +#define EXTRAM_END EXTRAM_START + 8 KiB - 1 +#define EXTRAM_RANGE EXTRAM_START ... EXTRAM_END +#define WRAM_STR00 EXTRAM_END + 1 +#define WRAM_END00 WRAM_STR00 + 4 KiB - 1 +#define WRAM_STRNN WRAM_END00 + 1 +#define WRAM_ENDNN WRAM_STRNN + 4 KiB - 1 +#define WRAM_RNG00 WRAM_STR00 ... WRAM_END00 +#define WRAM_RNGNN WRAM_STRNN ... WRAM_ENDNN +#define OAM_START WRAM_ENDNN + 1 +#define OAM_END OAM_START + 0x9F +#define OAM_RANGE OAM_START ... OAM_END +#define UNUSABLE_START OAM_END + 1 +#define UNUSABLE_END UNUSABLE_START + 0x5F +#define UNUSABLE_RANGE UNUSABLE_START ... UNUSABLE_END +#define IO_START UNUSABLE_END + 1 +#define IO_END IO_START + 0x7F +#define IO_RANGE IO_START ... IO_END +#define HRAM_START IO_END + 1 +#define HRAM_END HRAM_START + 0x7E +#define HRAM_RANGE HRAM_START ... HRAM_END diff --git a/src/core/util.hpp b/src/core/util.hpp index cc44dc7f..fc0e3611 100644 --- a/src/core/util.hpp +++ b/src/core/util.hpp @@ -4,6 +4,12 @@ #include namespace natsukashii::util { +template +constexpr void panic(const std::string& fmt, Args... args) { + fmt::print(fmt, args...); + exit(-1); +} + template using BitSliceType = typename std::conditional<(end - start) <= 7, u8, @@ -29,4 +35,5 @@ T BitSlice(const T& num, int start, int end) { auto correctedEnd = end == (sizeof(T) * 8) - 1 ? end : end + 1; return (num >> start) & ((1 << correctedEnd) - 1); } + } diff --git a/src/frontend/sdl/Frontend.cpp b/src/frontend/sdl/Frontend.cpp index 75fcb8cf..a2c9bac3 100644 --- a/src/frontend/sdl/Frontend.cpp +++ b/src/frontend/sdl/Frontend.cpp @@ -16,9 +16,11 @@ App::App() { void App::Run() { while(!quit) { - SDL_Event e; - SDL_PollEvent(&e); - quit = e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_CLOSE && e.window.windowID == id; + gb.Run(); + + SDL_Event event; + SDL_PollEvent(&event); + quit = event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == id; } } }