all repos — mgba @ e79963b007a0feee6c241774609808061c288f1b

mGBA Game Boy Advance Emulator

GBA: Support printing debug strings from inside a game
Jeffrey Pfau jeffrey@endrift.com
Wed, 28 Sep 2016 14:37:48 -0700
commit

e79963b007a0feee6c241774609808061c288f1b

parent

278ac5f35bc089efe939466c957259bb66a59a9d

5 files changed, 60 insertions(+), 1 deletions(-)

jump to
M CHANGESCHANGES

@@ -1,4 +1,6 @@

0.6.0: (Future) +Features: + - GBA: Support printing debug strings from inside a game Bugfixes: - GB MBC: Fix MBC7 when size is incorrectly specified - GB Video: Setting LYC=LY during mode 2 should trigger an IRQ
M src/gba/gba.csrc/gba/gba.c

@@ -27,6 +27,7 @@ #include "util/patch.h"

#include "util/vfs.h" mLOG_DEFINE_CATEGORY(GBA, "GBA"); +mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug"); const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;

@@ -199,6 +200,9 @@ gba->lastJump = 0;

gba->haltPending = false; gba->idleDetectionStep = 0; gba->idleDetectionFailures = 0; + + gba->debug = false; + memset(gba->debugString, 0, sizeof(gba->debugString)); } void GBASkipBIOS(struct GBA* gba) {

@@ -679,6 +683,19 @@ return;

} gba->cpu->nextEvent = gba->cpu->cycles; gba->stopCallback->stop(gba->stopCallback); +} + +void GBADebug(struct GBA* gba, uint16_t flags) { + gba->debugFlags = flags; + if (GBADebugFlagsIsSend(gba->debugFlags)) { + int level = 1 << GBADebugFlagsGetLevel(gba->debugFlags); + level &= 0x1F; + char oolBuf[0x101]; + strncpy(oolBuf, gba->debugString, sizeof(gba->debugString)); + oolBuf[0x100] = '\0'; + mLog(_mLOG_CAT_GBA_DEBUG(), level, "%s", oolBuf); + } + gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags); } bool GBAIsROM(struct VFile* vf) {
M src/gba/gba.hsrc/gba/gba.h

@@ -53,12 +53,17 @@ struct Patch;

struct VFile; mLOG_DECLARE_CATEGORY(GBA); +mLOG_DECLARE_CATEGORY(GBA_DEBUG); DECL_BITFIELD(GBATimerFlags, uint32_t); DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4); DECL_BIT(GBATimerFlags, CountUp, 4); DECL_BIT(GBATimerFlags, DoIrq, 5); DECL_BIT(GBATimerFlags, Enable, 6); + +DECL_BITFIELD(GBADebugFlags, uint16_t); +DECL_BITS(GBADebugFlags, Level, 0, 3); +DECL_BIT(GBADebugFlags, Send, 8); struct GBATimer { uint16_t reload;

@@ -120,6 +125,10 @@

bool realisticTiming; bool hardCrash; bool allowOpposingDirections; + + bool debug; + char debugString[0x100]; + GBADebugFlags debugFlags; }; struct GBACartridge {

@@ -153,6 +162,7 @@ void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq);

void GBATestIRQ(struct ARMCore* cpu); void GBAHalt(struct GBA* gba); void GBAStop(struct GBA* gba); +void GBADebug(struct GBA* gba, uint16_t value); void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger); void GBADetachDebugger(struct GBA* gba);
M src/gba/io.csrc/gba/io.c

@@ -540,7 +540,20 @@ break;

case REG_MAX: // Some bad interrupt libraries will write to this break; + case REG_DEBUG_ENABLE: + gba->debug = value == 0xC0DE; + return; + case REG_DEBUG_FLAGS: + if (gba->debug) { + GBADebug(gba, value); + return; + } + // Fall through default: + if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { + STORE_16LE(value, address - REG_DEBUG_STRING, gba->debugString); + return; + } mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address); if (address >= REG_MAX) { mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address);

@@ -560,6 +573,10 @@ GBAHalt(gba);

} else { GBAStop(gba); } + return; + } + if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { + gba->debugString[address - REG_DEBUG_STRING] = value; return; } if (address > SIZE_IO) {

@@ -613,6 +630,10 @@ case REG_DMA3DAD_LO:

value = GBAMemoryWriteDMADAD(gba, 3, value); break; default: + if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { + STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString); + return; + } GBAIOWrite(gba, address, value & 0xFFFF); GBAIOWrite(gba, address | 2, value >> 16); return;

@@ -848,6 +869,11 @@ case 0x86:

case 0x8A: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return 0; + case REG_DEBUG_ENABLE: + if (gba->debug) { + return 0x1DEA; + } + // Fall through default: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return GBALoadBad(gba->cpu);
M src/gba/io.hsrc/gba/io.h

@@ -150,7 +150,11 @@

REG_MAX = 0x20A, REG_POSTFLG = 0x300, - REG_HALTCNT = 0x301 + REG_HALTCNT = 0x301, + + REG_DEBUG_STRING = 0xFFF600, + REG_DEBUG_FLAGS = 0xFFF700, + REG_DEBUG_ENABLE = 0xFFF780, }; mLOG_DECLARE_CATEGORY(GBA_IO);