diff --git a/include/mgba/core/cpu.h b/include/mgba/core/cpu.h index 71f3398c2..e538f4a59 100644 --- a/include/mgba/core/cpu.h +++ b/include/mgba/core/cpu.h @@ -20,6 +20,15 @@ enum mCPUComponentType { CPU_COMPONENT_MAX }; +enum mMemoryAccessSource { + mACCESS_UNKNOWN = 0, + mACCESS_PROGRAM, + mACCESS_DMA, + mACCESS_SYSTEM, + mACCESS_DECOMPRESS, + mACCESS_COPY, +}; + struct mCPUComponent { uint32_t id; void (*init)(void* cpu, struct mCPUComponent* component); diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index eb69faaf4..7cf89882b 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -111,6 +111,7 @@ struct mDebuggerEntryInfo { uint32_t newValue; enum mWatchpointType watchType; enum mWatchpointType accessType; + enum mMemoryAccessSource accessSource; } wp; struct { diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index 5f25acf90..5ef2da965 100644 --- a/include/mgba/internal/arm/arm.h +++ b/include/mgba/internal/arm/arm.h @@ -132,6 +132,8 @@ struct ARMMemory { uint32_t activeNonseqCycles16; int32_t (*stall)(struct ARMCore*, int32_t wait); void (*setActiveRegion)(struct ARMCore*, uint32_t address); + + enum mMemoryAccessSource accessSource; }; struct ARMCoprocessor { diff --git a/include/mgba/internal/sm83/sm83.h b/include/mgba/internal/sm83/sm83.h index 86b4d374b..7f0fabd7a 100644 --- a/include/mgba/internal/sm83/sm83.h +++ b/include/mgba/internal/sm83/sm83.h @@ -61,6 +61,8 @@ struct SM83Memory { uint16_t activeMask; uint16_t activeRegionEnd; void (*setActiveRegion)(struct SM83Core*, uint16_t address); + + enum mMemoryAccessSource accessSource; }; struct SM83InterruptHandler { diff --git a/src/arm/debugger/memory-debugger.c b/src/arm/debugger/memory-debugger.c index 7dce87795..b0b48423b 100644 --- a/src/arm/debugger/memory-debugger.c +++ b/src/arm/debugger/memory-debugger.c @@ -121,6 +121,7 @@ static void _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, en info.type.wp.newValue = newValue; info.type.wp.watchType = watchpoint->type; info.type.wp.accessType = type; + info.type.wp.accessSource = debugger->cpu->memory.accessSource; info.address = address; info.segment = 0; info.width = width; diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index e38eead03..d8275a970 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -69,9 +69,29 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum } offset &= -info->width; + mDebuggerAccessLogFlagsEx flagsEx = 0; int i; switch (reason) { case DEBUGGER_ENTER_WATCHPOINT: + switch (info->type.wp.accessSource) { + case mACCESS_PROGRAM: + flagsEx = mDebuggerAccessLogFlagsExFillAccessProgram(flagsEx); + break; + case mACCESS_DMA: + flagsEx = mDebuggerAccessLogFlagsExFillAccessDMA(flagsEx); + break; + case mACCESS_SYSTEM: + flagsEx = mDebuggerAccessLogFlagsExFillAccessSystem(flagsEx); + break; + case mACCESS_DECOMPRESS: + flagsEx = mDebuggerAccessLogFlagsExFillAccessDecompress(flagsEx); + break; + case mACCESS_COPY: + flagsEx = mDebuggerAccessLogFlagsExFillAccessCopy(flagsEx); + break; + case mACCESS_UNKNOWN: + break; + } for (i = 0; i < info->width; ++i) { if (info->type.wp.accessType & WATCHPOINT_WRITE) { region->block[offset + i] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + i]); @@ -83,16 +103,29 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum switch (info->width) { case 1: region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + } break; case 2: region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + } break; case 4: region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + region->blockEx[offset + 2] |= flagsEx; + region->blockEx[offset + 3] |= flagsEx; + } break; case 8: region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); @@ -103,6 +136,16 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + region->blockEx[offset + 2] |= flagsEx; + region->blockEx[offset + 3] |= flagsEx; + region->blockEx[offset + 4] |= flagsEx; + region->blockEx[offset + 5] |= flagsEx; + region->blockEx[offset + 6] |= flagsEx; + region->blockEx[offset + 7] |= flagsEx; + } break; } break; diff --git a/src/gb/memory.c b/src/gb/memory.c index dccd91e08..fdacc1a9b 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -148,6 +148,7 @@ void GBMemoryInit(struct GB* gb) { cpu->memory.store8 = GBStore8; cpu->memory.currentSegment = GBCurrentSegment; cpu->memory.setActiveRegion = GBSetActiveRegion; + cpu->memory.accessSource = mACCESS_UNKNOWN; gb->memory.wram = 0; gb->memory.wramBank = 0; @@ -205,6 +206,7 @@ void GBMemoryReset(struct GB* gb) { gb->memory.hdmaDest = 0; gb->memory.isHdma = false; + gb->cpu->memory.accessSource = mACCESS_UNKNOWN; gb->memory.dmaEvent.context = gb; gb->memory.dmaEvent.name = "GB DMA"; @@ -576,10 +578,13 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL struct GB* gb = context; int dmaRemaining = gb->memory.dmaRemaining; gb->memory.dmaRemaining = 0; + enum mMemoryAccessSource oldAccess = gb->cpu->memory.accessSource; + gb->cpu->memory.accessSource = mACCESS_DMA; uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource); // TODO: Can DMA write OAM during modes 2-3? gb->video.oam.raw[gb->memory.dmaDest] = b; gb->video.renderer->writeOAM(gb->video.renderer, gb->memory.dmaDest); + gb->cpu->memory.accessSource = oldAccess; ++gb->memory.dmaSource; ++gb->memory.dmaDest; gb->memory.dmaRemaining = dmaRemaining - 1; @@ -591,8 +596,11 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL void _GBMemoryHDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GB* gb = context; gb->cpuBlocked = true; + enum mMemoryAccessSource oldAccess = gb->cpu->memory.accessSource; + gb->cpu->memory.accessSource = mACCESS_DMA; uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource); gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b); + gb->cpu->memory.accessSource = oldAccess; ++gb->memory.hdmaSource; ++gb->memory.hdmaDest; --gb->memory.hdmaRemaining; diff --git a/src/gba/bios.c b/src/gba/bios.c index 1ff5004d3..c7b963a40 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -174,6 +174,8 @@ static void _BgAffineSet(struct GBA* gba) { int destination = cpu->gprs[1]; float a, b, c, d; float rx, ry; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; while (i--) { // [ sx 0 0 ] [ cos(theta) -sin(theta) 0 ] [ 1 0 cx - ox ] [ A B rx ] // [ 0 sy 0 ] * [ sin(theta) cos(theta) 0 ] * [ 0 1 cy - oy ] = [ C D ry ] @@ -205,6 +207,7 @@ static void _BgAffineSet(struct GBA* gba) { cpu->memory.store32(cpu, destination + 12, ry * 256, 0); destination += 16; } + cpu->memory.accessSource = oldAccess; } static void _ObjAffineSet(struct GBA* gba) { @@ -216,6 +219,8 @@ static void _ObjAffineSet(struct GBA* gba) { int destination = cpu->gprs[1]; int diff = cpu->gprs[3]; float a, b, c, d; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; while (i--) { // [ sx 0 ] [ cos(theta) -sin(theta) ] [ A B ] // [ 0 sy ] * [ sin(theta) cos(theta) ] = [ C D ] @@ -237,6 +242,7 @@ static void _ObjAffineSet(struct GBA* gba) { cpu->memory.store16(cpu, destination + diff * 3, d * 256, 0); destination += diff * 4; } + cpu->memory.accessSource = oldAccess; } static void _MidiKey2Freq(struct GBA* gba) { @@ -244,7 +250,10 @@ static void _MidiKey2Freq(struct GBA* gba) { int oldRegion = gba->memory.activeRegion; gba->memory.activeRegion = GBA_REGION_BIOS; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; uint32_t key = cpu->memory.load32(cpu, cpu->gprs[0] + 4, 0); + cpu->memory.accessSource = oldAccess; gba->memory.activeRegion = oldRegion; cpu->gprs[0] = key / exp2f((180.f - cpu->gprs[1] - cpu->gprs[2] / 256.f) / 12.f); @@ -624,6 +633,8 @@ static void _unLz77(struct GBA* gba, int width) { uint32_t source = cpu->gprs[0]; uint32_t dest = cpu->gprs[1]; int cycles = 20; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; int remaining = (cpu->memory.load32(cpu, source, &cycles) & 0xFFFFFF00) >> 8; // We assume the signature byte (0x10) is correct int blockheader = 0; // Some compilers warn if this isn't set, even though it's trivially provably always set @@ -698,6 +709,7 @@ static void _unLz77(struct GBA* gba, int width) { blocksRemaining = 8; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; cpu->gprs[3] = 0; @@ -713,6 +725,8 @@ static void _unHuffman(struct GBA* gba) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC; uint32_t dest = cpu->gprs[1]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; uint32_t header = cpu->memory.load32(cpu, source, 0); int remaining = header >> 8; unsigned bits = header & 0xF; @@ -722,6 +736,7 @@ static void _unHuffman(struct GBA* gba) { } if (32 % bits || bits == 1) { mLOG(GBA_BIOS, STUB, "Unimplemented unaligned Huffman"); + cpu->memory.accessSource = oldAccess; return; } // We assume the signature byte (0x20) is correct @@ -773,6 +788,7 @@ static void _unHuffman(struct GBA* gba) { } } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -780,6 +796,8 @@ static void _unHuffman(struct GBA* gba) { static void _unRl(struct GBA* gba, int width) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; int remaining = (cpu->memory.load32(cpu, source & 0xFFFFFFFC, 0) & 0xFFFFFF00) >> 8; int padding = (4 - remaining) & 0x3; // We assume the signature byte (0x30) is correct @@ -846,6 +864,7 @@ static void _unRl(struct GBA* gba, int width) { ++dest; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -854,6 +873,8 @@ static void _unFilter(struct GBA* gba, int inwidth, int outwidth) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC; uint32_t dest = cpu->gprs[1]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; uint32_t header = cpu->memory.load32(cpu, source, 0); int remaining = header >> 8; // We assume the signature nybble (0x8) is correct @@ -888,6 +909,7 @@ static void _unFilter(struct GBA* gba, int inwidth, int outwidth) { old = new; source += inwidth; } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -897,6 +919,8 @@ static void _unBitPack(struct GBA* gba) { uint32_t source = cpu->gprs[0]; uint32_t dest = cpu->gprs[1]; uint32_t info = cpu->gprs[2]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; unsigned sourceLen = cpu->memory.load16(cpu, info, 0); unsigned sourceWidth = cpu->memory.load8(cpu, info + 2, 0); unsigned destWidth = cpu->memory.load8(cpu, info + 3, 0); @@ -908,6 +932,7 @@ static void _unBitPack(struct GBA* gba) { break; default: mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source width: %u", sourceWidth); + cpu->memory.accessSource = oldAccess; return; } switch (destWidth) { @@ -920,6 +945,7 @@ static void _unBitPack(struct GBA* gba) { break; default: mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination width: %u", destWidth); + cpu->memory.accessSource = oldAccess; return; } uint32_t bias = cpu->memory.load32(cpu, info + 4, 0); @@ -949,6 +975,7 @@ static void _unBitPack(struct GBA* gba) { dest += 4; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } diff --git a/src/gba/dma.c b/src/gba/dma.c index e9044d26a..3e3e8222d 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -248,10 +248,12 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { uint32_t dest = info->nextDest; uint32_t sourceRegion = source >> BASE_OFFSET; uint32_t destRegion = dest >> BASE_OFFSET; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; int32_t cycles = 2; gba->cpuBlocked = true; gba->performingDMA = 1 | (number << 1); + cpu->memory.accessSource = mACCESS_DMA; if (info->count == info->nextCount) { if (width == 4) { @@ -315,6 +317,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { --info->nextCount; gba->performingDMA = 0; + cpu->memory.accessSource = oldAccess; int i; for (i = 0; i < 4; ++i) { diff --git a/src/gba/memory.c b/src/gba/memory.c index 4f074657a..27e289c8e 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -82,6 +82,7 @@ void GBAMemoryInit(struct GBA* gba) { cpu->memory.activeSeqCycles16 = 0; cpu->memory.activeNonseqCycles32 = 0; cpu->memory.activeNonseqCycles16 = 0; + cpu->memory.accessSource = mACCESS_UNKNOWN; gba->memory.biosPrefetch = 0; gba->memory.agbPrintProtect = 0; @@ -132,6 +133,7 @@ void GBAMemoryReset(struct GBA* gba) { gba->memory.prefetch = false; gba->memory.lastPrefetchedPc = 0; + gba->cpu->memory.accessSource = mACCESS_UNKNOWN; if (!gba->memory.wram || !gba->memory.iwram) { GBAMemoryDeinit(gba); @@ -299,22 +301,27 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { memory->activeRegion = newRegion; switch (newRegion) { case GBA_REGION_BIOS: + cpu->memory.accessSource = mACCESS_SYSTEM; cpu->memory.activeRegion = memory->bios; cpu->memory.activeMask = GBA_SIZE_BIOS - 1; break; case GBA_REGION_EWRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->wram; cpu->memory.activeMask = GBA_SIZE_EWRAM - 1; break; case GBA_REGION_IWRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->iwram; cpu->memory.activeMask = GBA_SIZE_IWRAM - 1; break; case GBA_REGION_PALETTE_RAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = (uint32_t*) gba->video.palette; cpu->memory.activeMask = GBA_SIZE_PALETTE_RAM - 1; break; case GBA_REGION_VRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; if (address & 0x10000) { cpu->memory.activeRegion = (uint32_t*) &gba->video.vram[0x8000]; cpu->memory.activeMask = 0x00007FFF; @@ -324,6 +331,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } break; case GBA_REGION_OAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = (uint32_t*) gba->video.oam.raw; cpu->memory.activeMask = GBA_SIZE_OAM - 1; break; @@ -333,6 +341,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { case GBA_REGION_ROM1_EX: case GBA_REGION_ROM2: case GBA_REGION_ROM2_EX: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->rom; cpu->memory.activeMask = memory->romMask; if ((address & (GBA_SIZE_ROM0 - 1)) < memory->romSize) { @@ -345,6 +354,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } // Fall through default: + cpu->memory.accessSource = mACCESS_UNKNOWN; memory->activeRegion = -1; cpu->memory.activeRegion = (uint32_t*) _deadbeef; cpu->memory.activeMask = 0; diff --git a/src/sm83/debugger/memory-debugger.c b/src/sm83/debugger/memory-debugger.c index a35c2afeb..345dc50bf 100644 --- a/src/sm83/debugger/memory-debugger.c +++ b/src/sm83/debugger/memory-debugger.c @@ -61,6 +61,7 @@ static void _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, e info.type.wp.newValue = newValue; info.type.wp.watchType = watchpoint->type; info.type.wp.accessType = type; + info.type.wp.accessSource = debugger->cpu->memory.accessSource; info.address = address; info.segment = debugger->originalMemory.currentSegment(debugger->cpu, address); info.width = 1;