mirror of https://github.com/mgba-emu/mgba.git
Debugger: Keep track of global cycle count
This commit is contained in:
parent
d7ecdb5e4e
commit
7f64f8cf3b
1
CHANGES
1
CHANGES
|
@ -40,6 +40,7 @@ Other fixes:
|
||||||
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
|
||||||
- Qt: Fix OpenGL 2.1 support (fixes mgba.io/i/1678)
|
- Qt: Fix OpenGL 2.1 support (fixes mgba.io/i/1678)
|
||||||
Misc:
|
Misc:
|
||||||
|
- Debugger: Keep track of global cycle count
|
||||||
- FFmpeg: Add looping option for GIF/APNG
|
- FFmpeg: Add looping option for GIF/APNG
|
||||||
- Qt: Renderer can be changed while a game is running
|
- Qt: Renderer can be changed while a game is running
|
||||||
- Qt: Add hex index to palette view
|
- Qt: Add hex index to palette view
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct mTiming {
|
||||||
struct mTimingEvent* root;
|
struct mTimingEvent* root;
|
||||||
struct mTimingEvent* reroot;
|
struct mTimingEvent* reroot;
|
||||||
|
|
||||||
|
uint64_t globalCycles;
|
||||||
uint32_t masterCycles;
|
uint32_t masterCycles;
|
||||||
int32_t* relativeCycles;
|
int32_t* relativeCycles;
|
||||||
int32_t* nextEvent;
|
int32_t* nextEvent;
|
||||||
|
@ -38,6 +39,7 @@ void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*);
|
||||||
bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*);
|
bool mTimingIsScheduled(const struct mTiming* timing, const struct mTimingEvent*);
|
||||||
int32_t mTimingTick(struct mTiming* timing, int32_t cycles);
|
int32_t mTimingTick(struct mTiming* timing, int32_t cycles);
|
||||||
int32_t mTimingCurrentTime(const struct mTiming* timing);
|
int32_t mTimingCurrentTime(const struct mTiming* timing);
|
||||||
|
uint64_t mTimingGlobalTime(const struct mTiming* timing);
|
||||||
int32_t mTimingNextEvent(struct mTiming* timing);
|
int32_t mTimingNextEvent(struct mTiming* timing);
|
||||||
int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*);
|
int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent*);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,8 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
|
||||||
* | bit 4: Is HDMA active?
|
* | bit 4: Is HDMA active?
|
||||||
* | bits 5 - 7: Active RTC register
|
* | bits 5 - 7: Active RTC register
|
||||||
* | 0x00196 - 0x00197: Reserved (leave zero)
|
* | 0x00196 - 0x00197: Reserved (leave zero)
|
||||||
* 0x00198 - 0x0025F: Reserved (leave zero)
|
* 0x00198 - 0x0019F: Global cycle counter
|
||||||
|
* 0x001A0 - 0x0025F: Reserved (leave zero)
|
||||||
* 0x00260 - 0x002FF: OAM
|
* 0x00260 - 0x002FF: OAM
|
||||||
* 0x00300 - 0x0037F: I/O memory
|
* 0x00300 - 0x0037F: I/O memory
|
||||||
* 0x00380 - 0x003FE: HRAM
|
* 0x00380 - 0x003FE: HRAM
|
||||||
|
@ -388,7 +389,9 @@ struct GBSerializedState {
|
||||||
uint16_t reserved;
|
uint16_t reserved;
|
||||||
} memory;
|
} memory;
|
||||||
|
|
||||||
uint32_t reserved[50];
|
uint64_t globalCycles;
|
||||||
|
|
||||||
|
uint32_t reserved[48];
|
||||||
|
|
||||||
uint8_t oam[GB_SIZE_OAM];
|
uint8_t oam[GB_SIZE_OAM];
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
|
||||||
* | 0x002F4 - 0x002F7: GBA BIOS bus prefetch
|
* | 0x002F4 - 0x002F7: GBA BIOS bus prefetch
|
||||||
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot)
|
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot)
|
||||||
* | 0x002FC - 0x002FF: CPU prefetch (fetch slot)
|
* | 0x002FC - 0x002FF: CPU prefetch (fetch slot)
|
||||||
* 0x00300 - 0x00317: Reserved (leave zero)
|
* 0x00300 - 0x0030F: Reserved (leave zero)
|
||||||
|
* 0x00310 - 0x00317: Global cycle counter
|
||||||
* 0x00318 - 0x0031B: Last prefetched program counter
|
* 0x00318 - 0x0031B: Last prefetched program counter
|
||||||
* 0x0031C - 0x0031F: Miscellaneous flags
|
* 0x0031C - 0x0031F: Miscellaneous flags
|
||||||
* | bit 0: Is CPU halted?
|
* | bit 0: Is CPU halted?
|
||||||
|
@ -326,8 +327,9 @@ struct GBASerializedState {
|
||||||
uint32_t biosPrefetch;
|
uint32_t biosPrefetch;
|
||||||
uint32_t cpuPrefetch[2];
|
uint32_t cpuPrefetch[2];
|
||||||
|
|
||||||
uint32_t reservedCpu[6];
|
uint32_t reservedCpu[4];
|
||||||
|
|
||||||
|
uint64_t globalCycles;
|
||||||
uint32_t lastPrefetchedPc;
|
uint32_t lastPrefetchedPc;
|
||||||
GBASerializedMiscFlags miscFlags;
|
GBASerializedMiscFlags miscFlags;
|
||||||
uint32_t nextIrq;
|
uint32_t nextIrq;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <mgba/internal/arm/debugger/cli-debugger.h>
|
#include <mgba/internal/arm/debugger/cli-debugger.h>
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
|
#include <mgba/core/timing.h>
|
||||||
#include <mgba/internal/arm/debugger/debugger.h>
|
#include <mgba/internal/arm/debugger/debugger.h>
|
||||||
#include <mgba/internal/arm/debugger/memory-debugger.h>
|
#include <mgba/internal/arm/debugger/memory-debugger.h>
|
||||||
#include <mgba/internal/arm/decoder.h>
|
#include <mgba/internal/arm/decoder.h>
|
||||||
|
@ -138,6 +139,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
||||||
}
|
}
|
||||||
be->printf(be, "cpsr: ");
|
be->printf(be, "cpsr: ");
|
||||||
_printPSR(be, cpu->cpsr);
|
_printPSR(be, cpu->cpsr);
|
||||||
|
be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
|
||||||
int instructionLength;
|
int instructionLength;
|
||||||
enum ExecutionMode mode = cpu->cpsr.t;
|
enum ExecutionMode mode = cpu->cpsr.t;
|
||||||
if (mode == MODE_ARM) {
|
if (mode == MODE_ARM) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) {
|
void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextEvent) {
|
||||||
timing->root = NULL;
|
timing->root = NULL;
|
||||||
timing->reroot = NULL;
|
timing->reroot = NULL;
|
||||||
|
timing->globalCycles = 0;
|
||||||
timing->masterCycles = 0;
|
timing->masterCycles = 0;
|
||||||
timing->relativeCycles = relativeCycles;
|
timing->relativeCycles = relativeCycles;
|
||||||
timing->nextEvent = nextEvent;
|
timing->nextEvent = nextEvent;
|
||||||
|
@ -20,6 +21,7 @@ void mTimingDeinit(struct mTiming* timing) {
|
||||||
void mTimingClear(struct mTiming* timing) {
|
void mTimingClear(struct mTiming* timing) {
|
||||||
timing->root = NULL;
|
timing->root = NULL;
|
||||||
timing->reroot = NULL;
|
timing->reroot = NULL;
|
||||||
|
timing->globalCycles = 0;
|
||||||
timing->masterCycles = 0;
|
timing->masterCycles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +105,10 @@ int32_t mTimingCurrentTime(const struct mTiming* timing) {
|
||||||
return timing->masterCycles + *timing->relativeCycles;
|
return timing->masterCycles + *timing->relativeCycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t mTimingGlobalTime(const struct mTiming* timing) {
|
||||||
|
return timing->globalCycles + *timing->relativeCycles;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t mTimingNextEvent(struct mTiming* timing) {
|
int32_t mTimingNextEvent(struct mTiming* timing) {
|
||||||
struct mTimingEvent* next = timing->root;
|
struct mTimingEvent* next = timing->root;
|
||||||
if (!next) {
|
if (!next) {
|
||||||
|
|
|
@ -674,6 +674,9 @@ void GBProcessEvents(struct SM83Core* cpu) {
|
||||||
int32_t nextEvent;
|
int32_t nextEvent;
|
||||||
|
|
||||||
cpu->cycles = 0;
|
cpu->cycles = 0;
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
gb->timing.globalCycles += cycles;
|
||||||
|
#endif
|
||||||
cpu->nextEvent = INT_MAX;
|
cpu->nextEvent = INT_MAX;
|
||||||
|
|
||||||
nextEvent = cycles;
|
nextEvent = cycles;
|
||||||
|
|
|
@ -23,6 +23,7 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
|
||||||
STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
|
STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic);
|
||||||
STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
|
STORE_32LE(gb->romCrc32, 0, &state->romCrc32);
|
||||||
STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
|
STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
|
||||||
|
STORE_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
|
||||||
|
|
||||||
if (gb->memory.rom) {
|
if (gb->memory.rom) {
|
||||||
memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title));
|
memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title));
|
||||||
|
@ -150,6 +151,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
||||||
}
|
}
|
||||||
mTimingClear(&gb->timing);
|
mTimingClear(&gb->timing);
|
||||||
LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
|
LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);
|
||||||
|
LOAD_64LE(gb->timing.globalCycles, 0, &state->globalCycles);
|
||||||
|
|
||||||
gb->cpu->a = state->cpu.a;
|
gb->cpu->a = state->cpu.a;
|
||||||
gb->cpu->f.packed = state->cpu.f;
|
gb->cpu->f.packed = state->cpu.f;
|
||||||
|
|
|
@ -277,6 +277,9 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
|
||||||
do {
|
do {
|
||||||
int32_t cycles = cpu->cycles;
|
int32_t cycles = cpu->cycles;
|
||||||
cpu->cycles = 0;
|
cpu->cycles = 0;
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
gba->timing.globalCycles += cycles;
|
||||||
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (cycles < 0) {
|
if (cycles < 0) {
|
||||||
mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
|
mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
|
||||||
|
|
|
@ -28,6 +28,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
||||||
STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
|
STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
|
||||||
STORE_32(gba->romCrc32, 0, &state->romCrc32);
|
STORE_32(gba->romCrc32, 0, &state->romCrc32);
|
||||||
STORE_32(gba->timing.masterCycles, 0, &state->masterCycles);
|
STORE_32(gba->timing.masterCycles, 0, &state->masterCycles);
|
||||||
|
STORE_64LE(gba->timing.globalCycles, 0, &state->globalCycles);
|
||||||
|
|
||||||
if (gba->memory.rom) {
|
if (gba->memory.rom) {
|
||||||
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
|
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
|
||||||
|
@ -128,6 +129,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||||
}
|
}
|
||||||
mTimingClear(&gba->timing);
|
mTimingClear(&gba->timing);
|
||||||
LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles);
|
LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles);
|
||||||
|
LOAD_64LE(gba->timing.globalCycles, 0, &state->globalCycles);
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < 16; ++i) {
|
for (i = 0; i < 16; ++i) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <mgba/internal/sm83/debugger/cli-debugger.h>
|
#include <mgba/internal/sm83/debugger/cli-debugger.h>
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
|
#include <mgba/core/timing.h>
|
||||||
#include <mgba/internal/debugger/cli-debugger.h>
|
#include <mgba/internal/debugger/cli-debugger.h>
|
||||||
#include <mgba/internal/sm83/decoder.h>
|
#include <mgba/internal/sm83/decoder.h>
|
||||||
#include <mgba/internal/sm83/debugger/debugger.h>
|
#include <mgba/internal/sm83/debugger/debugger.h>
|
||||||
|
@ -88,6 +89,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
|
||||||
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
|
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
|
||||||
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
|
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
|
||||||
_printFlags(be, cpu->f);
|
_printFlags(be, cpu->f);
|
||||||
|
be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing));
|
||||||
|
|
||||||
struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform;
|
struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
Loading…
Reference in New Issue