From 6725b4545adc3e94e0344e5f904267349ce167ba Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Thu, 28 Nov 2013 22:05:32 +0200 Subject: [PATCH 3/9] Breakpoints & debugging --- libgambatte/include/gambatte.h | 23 +++++++++ libgambatte/src/cpu.cpp | 9 ++-- libgambatte/src/cpu.h | 7 +++ libgambatte/src/gambatte.cpp | 16 ++++++ libgambatte/src/mem/cartridge.cpp | 6 +++ libgambatte/src/mem/cartridge.h | 1 + libgambatte/src/memory.cpp | 100 ++++++++++++++++++++++++++++++-------- libgambatte/src/memory.h | 93 ++++++++++++++++++++++++++++++++--- 8 files changed, 225 insertions(+), 30 deletions(-) diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 5094906..ea2558c 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -18,6 +18,7 @@ ***************************************************************************/ #ifndef GAMBATTE_H #define GAMBATTE_H +#define GAMBATTE_SUPPORTS_ADV_DEBUG #include "gbint.h" #include "inputgetter.h" @@ -25,6 +26,8 @@ #include #include #include +#include +#include // // Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara @@ -34,6 +37,23 @@ namespace gambatte { enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 }; +struct debugbuffer +{ + //1 => Read, 2 => Write, 4 => Execute, 8 => Cheat + uint8_t* wram; //32kB, id1. + uint8_t* ioamhram; //512 bytes, id2. + uint8_t* cart; //As needed, id3. + uint8_t* sram; //As needed, id4. + uint8_t* bus; //64kB, id0 + std::map wramcheat; + std::map sramcheat; + std::map cartcheat; + std::function read; + std::function write; + std::function trace; + bool trace_cpu; +}; + class GB { public: GB(); @@ -259,6 +279,9 @@ public: }; uint32_t get_cpureg(enum cpu_register reg); void set_cpureg(enum cpu_register reg, uint32_t val); + void set_debug_buffer(debugbuffer& dbgbuf); + uint8_t bus_read(unsigned addr); + void bus_write(unsigned addr, uint8_t val); private: void preload_common(); void postload_common(const unsigned flags); diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp index 06400c5..40a81e6 100644 --- a/libgambatte/src/cpu.cpp +++ b/libgambatte/src/cpu.cpp @@ -154,8 +154,8 @@ void CPU::loadOrSave(loadsave& state) #define de() ( d << 8 | e ) #define hl() ( h << 8 | l ) -#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter); cycleCounter += 4; } while (0) -#define PC_READ(dest) do { (dest) = mem_.read(pc, cycleCounter); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0) +#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter, false); cycleCounter += 4; } while (0) +#define PC_READ(dest) do { (dest) = mem_.read(pc, cycleCounter, true); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0) #define FF_READ(dest, addr) do { (dest) = mem_.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0) #define WRITE(addr, data) do { mem_.write(addr, data, cycleCounter); cycleCounter += 4; } while (0) @@ -525,7 +525,8 @@ void CPU::process(unsigned const cycles) { } } else while (cycleCounter < mem_.nextEventTime()) { unsigned char opcode; - + if(__builtin_expect(mem_.get_debug()->trace_cpu, 0)) + mem_.get_debug()->trace(pc); PC_READ(opcode); if (skip_) { @@ -923,7 +924,7 @@ void CPU::process(unsigned const cycles) { case 0x3A: { unsigned addr = hl(); - a = mem_.read(addr, cycleCounter); + a = mem_.read(addr, cycleCounter, false); cycleCounter += 4; addr = (addr - 1) & 0xFFFF; diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 224ba0b..e7e46ff 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -51,6 +51,11 @@ public: mem_.setSaveDir(sdir); } + void set_debug_buffer(debugbuffer& dbgbuf) + { + mem_.set_debug_buffer(dbgbuf); + } + std::string const saveBasePath() const { return mem_.saveBasePath(); } @@ -87,6 +92,8 @@ public: std::pair getSaveRam() { return mem_.getSaveRam(); } std::pair getIoRam() { return mem_.getIoRam(); } std::pair getVideoRam() { return mem_.getVideoRam(); }; + uint8_t bus_read(unsigned addr) { return mem_.read(addr, cycleCounter_, false); } + void bus_write(unsigned addr, uint8_t val) { mem_.write(addr, val, cycleCounter_); } unsigned cycleCounter_; unsigned short pc_; diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index a61e177..47f894e 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -346,4 +346,20 @@ void GB::set_cpureg(enum cpu_register _reg, uint32_t val) default: break; } } + +void GB::set_debug_buffer(debugbuffer& dbgbuf) +{ + p_->cpu.set_debug_buffer(dbgbuf); +} + +uint8_t GB::bus_read(unsigned addr) +{ + return p_->cpu.bus_read(addr); +} + +void GB::bus_write(unsigned addr, uint8_t val) +{ + p_->cpu.bus_write(addr, val); +} + } diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp index d593dc5..1775139 100644 --- a/libgambatte/src/mem/cartridge.cpp +++ b/libgambatte/src/mem/cartridge.cpp @@ -858,6 +858,12 @@ std::pair Cartridge::getWorkRam() { return std::make_pair(memptrs_.wramdata(0), worksize); } +std::pair Cartridge::getCartRom() +{ + size_t worksize = memptrs_.romdataend() - memptrs_.romdata(0); + return std::make_pair(memptrs_.romdata(0), worksize); +} + Cartridge::Cartridge(time_t (**_getCurrentTime)()) : rtc_(_getCurrentTime) { memoryCartridge = true; diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h index dd342b6..3a0466c 100644 --- a/libgambatte/src/mem/cartridge.h +++ b/libgambatte/src/mem/cartridge.h @@ -81,6 +81,7 @@ public: void loadOrSave(loadsave& state); void setRtcBase(time_t time) { rtc_.setBaseTime(time); } time_t getRtcBase() { return rtc_.getBaseTime(); } + std::pair getCartRom(); std::pair getWorkRam(); std::pair getSaveRam(); std::pair getVideoRam(); diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index cc76f96..c42af88 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -234,7 +234,7 @@ unsigned Memory::event(unsigned cc) { unsigned const src = dmaSrc++ & 0xFFFF; unsigned const data = (src & 0xE000) == 0x8000 || src > 0xFDFF ? 0xFF - : read(src, cc); + : read(src, cc, false); cc += 2 << doubleSpeed; @@ -550,18 +550,31 @@ static bool isInOamDmaConflictArea(OamDmaSrc const oamDmaSrc, unsigned const p, && p - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth; } -unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) { +unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc, bool exec) { if (p < 0xFF80) { if (lastOamDmaUpdate_ != disabled_time) { updateOamDma(cc); - if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0) + if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0) { return ioamhram_[oamDmaPos_]; + } } if (p < 0xC000) { - if (p < 0x8000) - return cart_.romdata(p >> 14)[p]; + if (p < 0x8000) { + const unsigned char* aaddr = cart_.romdata(p >> 14) + p; + auto a = cart_.getCartRom(); + if(aaddr >= a.first && aaddr < a.first + a.second) + if(__builtin_expect(dbg->cart[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) { + if(dbg->cart[aaddr - a.first] & (exec ? 0x44 : 0x11)) + dbg->read(3, aaddr - a.first, *aaddr, exec); + if(dbg->cart[aaddr - a.first] & 8) { + auto itr = dbg->cartcheat.find(aaddr - a.first); + if(itr != dbg->cartcheat.end()) return itr->second; + } + } + return *aaddr; + } if (p < 0xA000) { if (!lcd_.vramAccessible(cc)) @@ -570,23 +583,52 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) { return cart_.vrambankptr()[p]; } - if (cart_.rsrambankptr()) - return cart_.rsrambankptr()[p]; + if (cart_.rsrambankptr()) { + const unsigned char* aaddr = cart_.rsrambankptr() + p; + auto a = cart_.getSaveRam(); + if(aaddr >= a.first && aaddr < a.first + a.second) + if(__builtin_expect(dbg->sram[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) { + if(dbg->sram[aaddr - a.first] & (exec ? 0x44 : 0x11)) + dbg->read(4, aaddr - a.first, *aaddr, exec); + if(dbg->sram[aaddr - a.first] & 8) { + auto itr = dbg->sramcheat.find(aaddr - a.first); + if(itr != dbg->sramcheat.end()) return itr->second; + } + } + return *aaddr; + } return cart_.rtcRead(); } - if (p < 0xFE00) - return cart_.wramdata(p >> 12 & 1)[p & 0xFFF]; + if (p < 0xFE00) { + unsigned char* aaddr = cart_.wramdata(p >> 12 & 1) + (p & 0xFFF); + auto a = cart_.getWorkRam(); + if(aaddr >= a.first && aaddr < a.first + a.second) + if(__builtin_expect(dbg->wram[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) { + if(dbg->wram[aaddr - a.first] & (exec ? 0x44 : 0x11)) + dbg->read(1, aaddr - a.first, *aaddr, exec); + if(dbg->wram[aaddr - a.first] & 8) { + auto itr = dbg->wramcheat.find(aaddr - a.first); + if(itr != dbg->wramcheat.end()) return itr->second; + } + } + return *aaddr; + } long const ffp = long(p) - 0xFF00; - if (ffp >= 0) - return nontrivial_ff_read(ffp, cc); + if (ffp >= 0) { + uint8_t v = nontrivial_ff_read(ffp, cc); + if(__builtin_expect(dbg->ioamhram[ffp + 0x100] & (exec ? 0x44 : 0x11), 0)) + dbg->read(2, ffp + 0x100, v, exec); + return v; + } if (!lcd_.oamReadable(cc) || oamDmaPos_ < 0xA0) return 0xFF; } - + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & (exec ? 0x44 : 0x11), 0)) + dbg->read(2, p - 0xFE00, ioamhram_[p - 0xFE00], exec); return ioamhram_[p - 0xFE00]; } @@ -1023,18 +1065,32 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned co if (p < 0xFE00) { if (p < 0xA000) { if (p < 0x8000) { + //Being a write on MBC, this is not ROM write. cart_.mbcWrite(p, data); } else if (lcd_.vramAccessible(cc)) { lcd_.vramChange(cc); cart_.vrambankptr()[p] = data; } } else if (p < 0xC000) { - if (cart_.wsrambankptr()) - cart_.wsrambankptr()[p] = data; - else + if (cart_.wsrambankptr()) { + unsigned char* aaddr = cart_.wsrambankptr() + p; + auto a = cart_.getSaveRam(); + if(aaddr >= a.first && aaddr < a.first + a.second) + if(__builtin_expect(dbg->sram[aaddr - a.first] & 0x22, 0)) + dbg->write(4, aaddr - a.first, data); + *aaddr = data; + } else { + //Being I/O write, this is not write on SRAM. cart_.rtcWrite(data); - } else - cart_.wramdata(p >> 12 & 1)[p & 0xFFF] = data; + } + } else { + unsigned char* aaddr = cart_.wramdata(p >> 12 & 1) + (p & 0xFFF); + auto a = cart_.getWorkRam(); + if(aaddr >= a.first && aaddr < a.first + a.second) + if(__builtin_expect(dbg->wram[aaddr - a.first] & 0x22, 0)) + dbg->write(1, aaddr - a.first, data); + *aaddr = data; + } } else if (p - 0xFF80u >= 0x7Fu) { long const ffp = long(p) - 0xFF00; if (ffp < 0) { @@ -1042,10 +1098,16 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned co lcd_.oamChange(cc); ioamhram_[p - 0xFE00] = data; } - } else + } else { + if(__builtin_expect(dbg->ioamhram[ffp + 0x100] & 0x22, 0)) + dbg->write(2, ffp + 0x100, data); nontrivial_ff_write(ffp, data, cc); - } else + } + } else { + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & 0x22, 0)) + dbg->write(2, p - 0xFE00, data); ioamhram_[p - 0xFE00] = data; + } } void Memory::postLoadRom() diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index a531930..4a252b7 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -23,6 +23,7 @@ // Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara // - Make it rerecording-friendly. +#include "gambatte.h" #include "mem/cartridge.h" #include "interrupter.h" #include "pakinfo.h" @@ -71,22 +72,99 @@ public: void ei(unsigned cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } } void di() { intreq_.di(); } + void set_debug_buffer(debugbuffer& dbgbuf) + { + dbg = &dbgbuf; + } + unsigned ff_read(unsigned p, unsigned cc) { - return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100]; + uint8_t v = p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100]; + if(__builtin_expect(dbg->ioamhram[0x100 + p] & 1, 0)) + dbg->read(2, 0x100 + p, v, false); + if(__builtin_expect(dbg->bus[0xFF00 + p] & 1, 0)) + dbg->read(0, 0xFF00 + p, v, false); + return v; + } + + inline uint8_t do_read_trap(const uint8_t* addr, std::pair area, unsigned clazz, + const uint8_t* dbgflags, std::map& cheats, uint8_t v, uint8_t mask, bool exec) + { + if(addr >= area.first && addr < area.first + area.second) { + if(__builtin_expect(dbgflags[addr - area.first] & mask, 0)) { + if(dbgflags[addr - area.first] & (mask & 77)) + dbg->read(clazz, addr - area.first, v, exec); + if(__builtin_expect(dbgflags[addr - area.first] & 8, 0)) { + auto itr = cheats.find(addr - area.first); + if(itr != cheats.end()) v = itr->second; + } + } + } + return v; } - unsigned read(unsigned p, unsigned cc) { - return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc); + inline void do_write_trap(const uint8_t* addr, std::pair area, unsigned clazz, + const uint8_t* dbgflags, uint8_t v) + { + if(addr >= area.first && addr < area.first + area.second) + if(__builtin_expect(dbgflags[addr - area.first] & 0x22, 0)) + dbg->write(clazz, addr - area.first, v); + } + + unsigned read(unsigned p, unsigned cc, bool exec) { + uint8_t mask = exec ? 0x4C : 0x19; + const unsigned char* memblock = cart_.rmem(p >> 12); + uint8_t v = memblock ? memblock[p] : nontrivial_read(p, cc, exec); + uint8_t v2 = v; + if(memblock) { + if(p >= 0xFE00) { //IOAMHRAM. + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & mask, 0)) + dbg->read(2, 0x100 + p, v, false); + } else { + const uint8_t* addr = memblock + p; + static void* targets[8] = {&&cart, &&cart, &&cart, &&cart, &&out, &&sram, &&wram, + &&wram}; + goto *targets[p >> 13]; +wram: + v2 = do_read_trap(addr, cart_.getWorkRam(), 1, dbg->wram, dbg->wramcheat, v, mask, exec); + goto out; +sram: + v2 = do_read_trap(addr, cart_.getSaveRam(), 4, dbg->sram, dbg->sramcheat, v, mask, exec); + goto out; +cart: + v2 = do_read_trap(addr, cart_.getCartRom(), 3, dbg->cart, dbg->cartcheat, v, mask, exec); + goto out; + } +out: ; + } + if(__builtin_expect(dbg->bus[p] & mask, 0)) + dbg->read(0, p, v, false); + return v2; } void write(unsigned p, unsigned data, unsigned cc) { - if (cart_.wmem(p >> 12)) { - cart_.wmem(p >> 12)[p] = data; + if(__builtin_expect(dbg->bus[0xFF00 + p] & 0x22, 0)) + dbg->write(0, p, data); + unsigned char* memblock = cart_.wmem(p >> 12); + if(memblock) { + if(p >= 0xFE00) //IOAMHRAM. + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & 2, 0)) + dbg->write(2, 0x100 + p, data); + uint8_t* addr = memblock + p; + do_write_trap(addr, cart_.getWorkRam(), 1, dbg->wram, data); + do_write_trap(addr, cart_.getSaveRam(), 4, dbg->sram, data); + do_write_trap(addr, cart_.getCartRom(), 3, dbg->cart, data); + } + if (memblock) { + memblock[p] = data; } else nontrivial_write(p, data, cc); } void ff_write(unsigned p, unsigned data, unsigned cc) { + if(__builtin_expect(dbg->ioamhram[0x100 + p] & 2, 0)) + dbg->write(2, 0x100 + p, data); + if(__builtin_expect(dbg->bus[0xFF00 + p] & 2, 0)) + dbg->write(0, 0xFF00 + p, data); if (p - 0x80u < 0x7Fu) { ioamhram_[p + 0x100] = data; } else @@ -119,8 +197,9 @@ public: void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32); void setGameGenie(std::string const &codes) { cart_.setGameGenie(codes); } void setGameShark(std::string const &codes) { interrupter_.setGameShark(codes); } - + debugbuffer* get_debug() { return dbg; } private: + debugbuffer* dbg; Cartridge cart_; unsigned char ioamhram_[0x200]; InputGetter *getInput_; @@ -147,7 +226,7 @@ private: void endOamDma(unsigned cycleCounter); unsigned char const * oamDmaSrcPtr() const; unsigned nontrivial_ff_read(unsigned p, unsigned cycleCounter); - unsigned nontrivial_read(unsigned p, unsigned cycleCounter); + unsigned nontrivial_read(unsigned p, unsigned cycleCounter, bool exec); void nontrivial_ff_write(unsigned p, unsigned data, unsigned cycleCounter); void nontrivial_write(unsigned p, unsigned data, unsigned cycleCounter); void updateSerial(unsigned cc); -- 2.1.3