LR35902: Add watchpoints

This commit is contained in:
Vicki Pfau 2017-06-02 19:15:13 -07:00
parent 39a73ecb95
commit 9c144266ec
8 changed files with 57 additions and 16 deletions

View File

@ -22,6 +22,7 @@ Features:
- GB: Symbol table support
- GB MBC: Add MBC1 multicart support
- GBA: Implement keypad interrupts
- LR35902: Watchpoints
Bugfixes:
- LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior

View File

@ -604,6 +604,7 @@ if(M_CORE_GB)
list(APPEND DEBUGGER_SRC
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/debugger.c
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/memory-debugger.c
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/cli.c
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c)
list(APPEND TEST_SRC

View File

@ -89,8 +89,8 @@ struct mDebuggerPlatform {
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address);
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*checkBreakpoints)(struct mDebuggerPlatform*);
};

View File

@ -12,6 +12,9 @@ CXX_GUARD_START
#include <mgba/internal/debugger/debugger.h>
#include <mgba/internal/lr35902/lr35902.h>
struct LR35902DebugBreakpoint {
uint16_t address;
int segment;
@ -32,6 +35,7 @@ struct LR35902Debugger {
struct LR35902DebugBreakpointList breakpoints;
struct LR35902DebugWatchpointList watchpoints;
struct LR35902Memory originalMemory;
};
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);

View File

@ -50,8 +50,8 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryRea
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
@ -182,7 +182,8 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
}
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) {
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerInstallMemoryShim(debugger);
@ -192,7 +193,8 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre
watchpoint->type = type;
}
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) {
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
size_t i;

View File

@ -428,7 +428,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
uint32_t address = dv->intValue;
debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_RW);
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW);
}
static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -441,7 +441,7 @@ static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVect
return;
}
uint32_t address = dv->intValue;
debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_READ);
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ);
}
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -454,7 +454,7 @@ static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
return;
}
uint32_t address = dv->intValue;
debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_WRITE);
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE);
}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@ -465,7 +465,7 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector
uint32_t address = dv->intValue;
debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue);
if (debugger->d.platform->clearWatchpoint) {
debugger->d.platform->clearWatchpoint(debugger->d.platform, address);
debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue);
}
}

View File

@ -498,13 +498,13 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
break;
case '2':
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE);
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE);
break;
case '3':
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ);
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ);
break;
case '4':
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW);
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW);
break;
default:
stub->outgoing[0] = '\0';
@ -529,7 +529,7 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
case '2':
case '3':
case '4':
stub->d.platform->clearWatchpoint(stub->d.platform, address);
stub->d.platform->clearWatchpoint(stub->d.platform, address, -1);
break;
default:
break;

View File

@ -7,6 +7,7 @@
#include <mgba/core/core.h>
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba/internal/lr35902/debugger/memory-debugger.h>
DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
@ -43,6 +44,8 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntr
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
@ -53,8 +56,8 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
platform->deinit = LR35902DebuggerDeinit;
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
platform->setWatchpoint = NULL;
platform->clearWatchpoint = NULL;
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
return platform;
@ -79,6 +82,10 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
struct LR35902Core* cpu = debugger->cpu;
cpu->nextEvent = cpu->cycles;
if (debugger->d.p->entered) {
debugger->d.p->entered(debugger->d.p, reason, info);
}
}
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@ -104,3 +111,29 @@ static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
}
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerInstallMemoryShim(debugger);
}
struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
watchpoint->segment = segment;
}
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints;
size_t i;
for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) {
struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i);
if (watchpoint->address == address && watchpoint->segment == segment) {
LR35902DebugWatchpointListShift(watchpoints, i, 1);
}
}
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerRemoveMemoryShim(debugger);
}
}