From: slack Date: Sun, 19 Aug 2007 02:39:00 +0000 (+0000) Subject: Mas cosas sobre memoria y MBCs X-Git-Tag: v0.1~73 X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=f3f3ac05deb7379798df9f1bc43218406c0249d7;p=wenboi.git Mas cosas sobre memoria y MBCs git-svn-id: http://slack.codemaniacs.com/wenboi@6 0666ae3d-8926-0410-aeff-ae84559ff337 --- diff --git a/GBMemory.cc b/GBMemory.cc new file mode 100644 index 0000000..c9d1345 --- /dev/null +++ b/GBMemory.cc @@ -0,0 +1,43 @@ +#include "GBMemory.h" +#include "MBC.h" +#include "gbcore.h" + +u8& GBMemory::operator[](unsigned int addr) +{ + if (addr < 0x8000) return (*mbc)[addr]; + else if (addr < 0xA000) return VRAM[addr-0x8000]; + else if (addr < 0xC000) return (*mbc)[addr]; + else if (addr < 0xD000) return WRAM0[addr-0xC000]; + else if (addr < 0xE000) return WRAM1[addr-0xD000]; + else if (addr < 0xFDFF) return (*mbc)[addr-0x2000]; + else if (addr < 0xFEA0) return OAM[addr-0xFDFF]; + else if (addr >= 0xFF00 && addr <= 0xFF7F) + return core->IO.addr[addr-0xFF00]; + else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80]; + else { + logger.error("Invalid write address"); + return *(static_cast(0)); + } +} + + +u8 GBMemory::operator[](unsigned int addr) const +{ + if (addr < 0x8000) return (*mbc)[addr]; + else if (addr < 0xA000) return VRAM[addr-0x8000]; + else if (addr < 0xC000) return (*mbc)[addr]; + else if (addr < 0xD000) return WRAM0[addr-0xC000]; + else if (addr < 0xE000) return WRAM1[addr-0xD000]; + else if (addr < 0xFDFF) return (*mbc)[addr-0x2000]; + else if (addr < 0xFEA0) return OAM[addr-0xFDFF]; + else if (addr >= 0xFF00 && addr <= 0xFF7F) + return core->IO.addr[addr-0xFF00]; + else if (addr >= 0xFF80 && addr <= 0xFFFE) return HRAM[addr-0xFF80]; + else { + logger.error("Invalid write address"); + return *(static_cast(0)); + } +} + + + diff --git a/GBMemory.h b/GBMemory.h index 8119c47..6e02479 100644 --- a/GBMemory.h +++ b/GBMemory.h @@ -2,10 +2,13 @@ #define GBMEMORY_H #include "sized_types.h" -#include "MBC.h" + +class GameBoy; +class MBC; class GBMemory { + GameBoy *core; MBC *mbc; // 0000-3FFF: ROM Bank 0 (in cart) // 4000-7FFF: Switchable ROM Bank (in cart) @@ -18,12 +21,12 @@ class GBMemory u8 HRAM[126]; // FF80-FFFE: High RAM public: - GBMemory(): mbc(0) {} + GBMemory(GameBoy *core): core(core), mbc(0) {} void init(MBC *mbc) { this->mbc = mbc; } - int& operator[](int index)=0; - int operator[](int index) const=0; + u8& operator[](unsigned int addr); + u8 operator[](unsigned int addr) const; }; diff --git a/GBRom.h b/GBRom.h index c88dd81..365f900 100644 --- a/GBRom.h +++ b/GBRom.h @@ -4,7 +4,7 @@ #include "sized_types.h" #include -namespace cartrigde_types { +namespace cartridge_types { const u8 ROM_ONLY=0x00; const u8 MBC1=0x01; const u8 MBC1_RAM=0x02; diff --git a/MBC.cc b/MBC.cc new file mode 100644 index 0000000..112ffa3 --- /dev/null +++ b/MBC.cc @@ -0,0 +1,16 @@ +#include "MBC.h" +#include "logger.h" + +using namespace cartridge_types; + +MBC *create_MBC(GBRom *rom) +{ + switch (rom->header.cartridge_type) + { + case ROM_ONLY: return new NoMBC(rom); + //case MBC1: return new MBC1(rom); + default: + logger.critical("Unsupported cartridge type"); + return 0; + } +} diff --git a/MBC.h b/MBC.h index 0d4baba..2f52f90 100644 --- a/MBC.h +++ b/MBC.h @@ -2,11 +2,48 @@ #define MBC_H #include "sized_types.h" +#include "GBRom.h" +#include "logger.h" +#include class MBC { - virtual u8 read_byte() const=0; - virtual void write_byte(u8)=0; + public: + virtual u8 operator[](unsigned int addr) const=0; + virtual u8& operator[](unsigned int addr)=0; + virtual ~MBC(); }; +class NoMBC: public MBC +{ + u8 ROM[32768]; + u8 RAM[8192]; + + public: + NoMBC(GBRom *rom) { memcpy(ROM, rom->data, 32768); } + + u8 operator[](unsigned int addr) const + { + if (addr <= 0x7FFF) + return ROM[addr]; + else if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF) + return RAM[addr-0xA000]; + else + logger.error("NoMBC: Incorrect read"); + return 0; + } + + u8& operator[](unsigned int addr) + { + if ((addr&0xE000) == 0xA000) //(addr >= 0xA000 && addr <= 0xBFFF) + return RAM[addr-0xA000]; + else + logger.error("NoMBC: trying to write in ROM"); + return *(static_cast(0)); // Shouldn't happen + } +}; + + +MBC *create_MBC(GBRom *rom); + #endif // MBC_H diff --git a/Makefile b/Makefile index 274c684..ca4ff79 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,23 @@ CXXFLAGS=-g -Wall -Weffc++ -Wstrict-null-sentinel -Wold-style-cast \ -Woverloaded-virtual -all: gbcore.o +all: gbcore.o MBC.o GBMemory.o logger.o tests: tests/test_gbrom -gbcore.o: gbcore.cc gbcore.h gbrom.h +logger.o: logger.cc logger.h + g++ $(CXXFLAGS) -c -o $@ $< + +GBMemory.o: GBMemory.cc GBMemory.h + g++ $(CXXFLAGS) -c -o $@ $< + +MBC.o: MBC.cc MBC.h + g++ $(CXXFLAGS) -c -o $@ $< + +gbcore.o: gbcore.cc gbcore.h GBRom.h logger.h MBC.h GBMemory.h g++ $(CXXFLAGS) -c -o $@ $< -tests/test_gbrom: gbrom.cc gbrom.h +tests/test_gbrom: GBRom.cc GBRom.h g++ -DTEST_GBROM -o $@ $< clean: diff --git a/gbcore.cc b/gbcore.cc index 9bd08e6..f9875ac 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -1,112 +1,26 @@ #include "gbcore.h" -#include "sized_types.h" #include "GBRom.h" -#include "GBMemory.h" #include "MBC.h" #include "logger.h" #include #include -class MBC -{ - virtual u8 read_byte() const=0; - virtual void write_byte(u8)=0; -}; - -class GBMemory -{ - MBC *mbc; - // 0000-3FFF: ROM Bank 0 (in cart) - // 4000-7FFF: Switchable ROM Bank (in cart) - u8 VRAM[8192]; // 8000-9FFF: Video RAM - // A000-BFFF: External RAM (in cart, switchable) - u8 WRAM0[4096]; // C000-CFFF: Work RAM Bank 0 - u8 WRAM1[4096]; // D000-DFFF: Work RAM Bank 1 (TODO: In GBC mode switchable bank 1-7) - // E000-FDFF: ECHO: Same as C000-DDFF - u8 OAM[160]; // FE00-FE9F: Sprite Attribute Table - u8 HRAM[126]; // FF80-FFFE: High RAM - - public: - GBMemory(): mbc(0) {} - void init(MBC *mbc) { this->mbc = mbc; } - - - int& operator[](int index)=0; - int operator[](int index) const=0; - -}; - -class GameBoy -{ - GBMemory memory; - GBRom *rom; - - enum flags_enum - { - ZERO_FLAG=0x80, - ADD_SUB_FLAG=0x40, - HALF_CARRY_FLAG=0x20, - CARRY_FLAG=0x10, - }; - - // CPU Registers - // ENDIANNESS WARNING! - struct - { - union - { - u16 AF; - struct { u8 flags; u8 A; }; - }; - union - { - u16 BC; - struct { u8 C; u8 B; }; - }; - union - { - u16 DE; - struct { u8 E; u8 D; }; - }; - union - { - u16 HL; - struct { u8 L; u8 H; }; - }; - u16 SP; - u16 PC; - - } __attribute__((packed)) regs; - - u8 IME; // Interrupt master enable flag - u8 HALT; // Is the CPU halted waiting for an interrupt? - - void set_flag(const u8 f) { regs.flags |= f; } - void reset_flag(const u8 f) { regs.flags &= (~f); } - bool check_flag(const u8 f) { return (regs.flags & f != 0); } - - public: - GameBoy(std::string rom_name); - - void reset(); - void run_cycle(); - void run(); - -}; - GameBoy::GameBoy(std::string rom_name): - rom(0), regs(), IME(1), HALT(0) + memory(this),rom(0), regs(), IO(), IME(1), HALT(0) { logger.info("GameBoy init"); rom = read_gbrom(rom_name); + + MBC *mbc = create_MBC(rom); + memory.init(mbc); + reset(); } void GameBoy::reset() { logger.info("GameBoy reset"); - std::memcpy(memory, rom->data, 16384); regs.PC = 0x100; } @@ -235,7 +149,7 @@ void GameBoy::run_cycle() // LD HL, SP+n // LDHL SP, n case 0xF8: { - s8 offset = *(reinterpret_cast(memory+regs.PC++)); + s8 offset = memory[regs.PC++]; int res = regs.SP + offset; // TODO: Verificar si los flags van asi @@ -488,7 +402,7 @@ void GameBoy::run_cycle() // ADD SP, # case 0xE8: { // FIXME: No se que hacer con el half carry, en 4 o en 11? - int n = *(reinterpret_cast(memory+regs.PC++)); + int n = static_cast(memory[regs.PC++]); int res = regs.SP + n; regs.SP = static_cast(res); reset_flag(ZERO_FLAG); diff --git a/gbcore.h b/gbcore.h index e69de29..5915453 100644 --- a/gbcore.h +++ b/gbcore.h @@ -0,0 +1,80 @@ +#ifndef GBCORE_H +#define GBCORE_H + +#include "sized_types.h" +#include "GBMemory.h" +#include + +union GBRom; + +class GameBoy +{ + friend class GBMemory; + GBMemory memory; + GBRom *rom; + + enum flags_enum + { + ZERO_FLAG=0x80, + ADD_SUB_FLAG=0x40, + HALF_CARRY_FLAG=0x20, + CARRY_FLAG=0x10, + }; + + // CPU Registers + // ENDIANNESS WARNING! + struct + { + union + { + u16 AF; + struct { u8 flags; u8 A; }; + }; + union + { + u16 BC; + struct { u8 C; u8 B; }; + }; + union + { + u16 DE; + struct { u8 E; u8 D; }; + }; + union + { + u16 HL; + struct { u8 L; u8 H; }; + }; + u16 SP; + u16 PC; + + } __attribute__((packed)) regs; + + + union + { + struct + { + }; + + u8 addr[128]; + + } IO; + + u8 IME; // Interrupt master enable flag + u8 HALT; // Is the CPU halted waiting for an interrupt? + + void set_flag(const u8 f) { regs.flags |= f; } + void reset_flag(const u8 f) { regs.flags &= (~f); } + bool check_flag(const u8 f) { return (regs.flags & f != 0); } + + public: + GameBoy(std::string rom_name); + + void reset(); + void run_cycle(); + void run(); + +}; + +#endif diff --git a/logger.h b/logger.h index 3649563..8d0138a 100644 --- a/logger.h +++ b/logger.h @@ -12,9 +12,6 @@ class Logger static Logger instance; public: - static Logger& getInstance() { return instance; } - Logger(std::ostream& os): out(os) {} - enum log_level{ OFF = -1, CRITICAL=0, @@ -25,6 +22,11 @@ class Logger TRACE=5 }; + static Logger& getInstance() { return instance; } + Logger(std::ostream& os): + out(os), + current_log_level(TRACE) {} + log_level current_log_level; @@ -40,6 +42,8 @@ class Logger void info (std::string str) { log(INFO , str); } void debug (std::string str) { log(DEBUG , str); } void trace (std::string str) { log(TRACE , str); } + + void set_log_level (log_level level) { current_log_level = level; } }; #define logger Logger::getInstance()