mirror of https://github.com/mgba-emu/mgba.git
LR35902: Add watchpoints
This commit is contained in:
parent
39a73ecb95
commit
9c144266ec
1
CHANGES
1
CHANGES
|
@ -22,6 +22,7 @@ Features:
|
||||||
- GB: Symbol table support
|
- GB: Symbol table support
|
||||||
- GB MBC: Add MBC1 multicart support
|
- GB MBC: Add MBC1 multicart support
|
||||||
- GBA: Implement keypad interrupts
|
- GBA: Implement keypad interrupts
|
||||||
|
- LR35902: Watchpoints
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- LR35902: Fix core never exiting with certain event patterns
|
- LR35902: Fix core never exiting with certain event patterns
|
||||||
- GB Timer: Improve DIV reset behavior
|
- GB Timer: Improve DIV reset behavior
|
||||||
|
|
|
@ -604,6 +604,7 @@ if(M_CORE_GB)
|
||||||
list(APPEND DEBUGGER_SRC
|
list(APPEND DEBUGGER_SRC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c
|
${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/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/cli.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c)
|
${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c)
|
||||||
list(APPEND TEST_SRC
|
list(APPEND TEST_SRC
|
||||||
|
|
|
@ -89,8 +89,8 @@ struct mDebuggerPlatform {
|
||||||
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
|
bool (*hasBreakpoints)(struct mDebuggerPlatform*);
|
||||||
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
|
void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
|
||||||
void (*clearBreakpoint)(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 (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
|
||||||
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address);
|
void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
|
||||||
void (*checkBreakpoints)(struct mDebuggerPlatform*);
|
void (*checkBreakpoints)(struct mDebuggerPlatform*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ CXX_GUARD_START
|
||||||
|
|
||||||
#include <mgba/internal/debugger/debugger.h>
|
#include <mgba/internal/debugger/debugger.h>
|
||||||
|
|
||||||
|
#include <mgba/internal/lr35902/lr35902.h>
|
||||||
|
|
||||||
|
|
||||||
struct LR35902DebugBreakpoint {
|
struct LR35902DebugBreakpoint {
|
||||||
uint16_t address;
|
uint16_t address;
|
||||||
int segment;
|
int segment;
|
||||||
|
@ -32,6 +35,7 @@ struct LR35902Debugger {
|
||||||
|
|
||||||
struct LR35902DebugBreakpointList breakpoints;
|
struct LR35902DebugBreakpointList breakpoints;
|
||||||
struct LR35902DebugWatchpointList watchpoints;
|
struct LR35902DebugWatchpointList watchpoints;
|
||||||
|
struct LR35902Memory originalMemory;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);
|
struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);
|
||||||
|
|
|
@ -50,8 +50,8 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryRea
|
||||||
|
|
||||||
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
|
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
|
||||||
static void ARMDebuggerClearBreakpoint(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 ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
|
||||||
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address);
|
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
|
||||||
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
|
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
|
||||||
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
|
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
|
||||||
|
|
||||||
|
@ -182,7 +182,8 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
|
||||||
return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints);
|
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;
|
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||||
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
|
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
|
||||||
ARMDebuggerInstallMemoryShim(debugger);
|
ARMDebuggerInstallMemoryShim(debugger);
|
||||||
|
@ -192,7 +193,8 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre
|
||||||
watchpoint->type = type;
|
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 ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||||
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
|
struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
|
@ -428,7 +428,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t address = dv->intValue;
|
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) {
|
static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
|
@ -441,7 +441,7 @@ static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVect
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t address = dv->intValue;
|
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) {
|
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||||
|
@ -454,7 +454,7 @@ static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t address = dv->intValue;
|
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) {
|
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;
|
uint32_t address = dv->intValue;
|
||||||
debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue);
|
debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue);
|
||||||
if (debugger->d.platform->clearWatchpoint) {
|
if (debugger->d.platform->clearWatchpoint) {
|
||||||
debugger->d.platform->clearWatchpoint(debugger->d.platform, address);
|
debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,13 +498,13 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
|
||||||
stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
|
stub->d.platform->setBreakpoint(stub->d.platform, address, -1);
|
||||||
break;
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE);
|
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE);
|
||||||
break;
|
break;
|
||||||
case '3':
|
case '3':
|
||||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ);
|
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ);
|
||||||
break;
|
break;
|
||||||
case '4':
|
case '4':
|
||||||
stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW);
|
stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stub->outgoing[0] = '\0';
|
stub->outgoing[0] = '\0';
|
||||||
|
@ -529,7 +529,7 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
|
||||||
case '2':
|
case '2':
|
||||||
case '3':
|
case '3':
|
||||||
case '4':
|
case '4':
|
||||||
stub->d.platform->clearWatchpoint(stub->d.platform, address);
|
stub->d.platform->clearWatchpoint(stub->d.platform, address, -1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba/internal/lr35902/lr35902.h>
|
#include <mgba/internal/lr35902/lr35902.h>
|
||||||
|
#include <mgba/internal/lr35902/debugger/memory-debugger.h>
|
||||||
|
|
||||||
DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
|
DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint);
|
||||||
DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint);
|
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 LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
|
||||||
static void LR35902DebuggerClearBreakpoint(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 void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
|
||||||
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
|
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
|
||||||
|
|
||||||
|
@ -53,8 +56,8 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
|
||||||
platform->deinit = LR35902DebuggerDeinit;
|
platform->deinit = LR35902DebuggerDeinit;
|
||||||
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
|
platform->setBreakpoint = LR35902DebuggerSetBreakpoint;
|
||||||
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
|
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
|
||||||
platform->setWatchpoint = NULL;
|
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
|
||||||
platform->clearWatchpoint = NULL;
|
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
|
||||||
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
|
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
|
||||||
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
|
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
|
||||||
return platform;
|
return platform;
|
||||||
|
@ -79,6 +82,10 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
|
||||||
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
|
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
|
||||||
struct LR35902Core* cpu = debugger->cpu;
|
struct LR35902Core* cpu = debugger->cpu;
|
||||||
cpu->nextEvent = cpu->cycles;
|
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) {
|
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;
|
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
|
||||||
return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue