GBA Memory: Prevent writing to mirrored BG VRAM (fixes #743)

This commit is contained in:
Vicki Pfau 2019-05-08 16:38:30 -07:00
parent e6f34e01f1
commit 0126330530
2 changed files with 46 additions and 37 deletions

View File

@ -22,6 +22,7 @@ Emulation fixes:
- GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340) - GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340)
- GBA Memory: Fix writing to OBJ memory in modes 3 and 5 - GBA Memory: Fix writing to OBJ memory in modes 3 and 5
- GBA: Fix RTC on non-standard sized ROMs (fixes mgba.io/i/1400) - GBA: Fix RTC on non-standard sized ROMs (fixes mgba.io/i/1400)
- GBA Memory: Prevent writing to mirrored BG VRAM (fixes mgba.io/i/743)
Other fixes: Other fixes:
- Qt: More app metadata fixes - Qt: More app metadata fixes
- Qt: Fix load recent from archive (fixes mgba.io/i/1325) - Qt: Fix load recent from archive (fixes mgba.io/i/1325)

View File

@ -390,11 +390,15 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
wait += waitstatesRegion[REGION_PALETTE_RAM]; wait += waitstatesRegion[REGION_PALETTE_RAM];
#define LOAD_VRAM \ #define LOAD_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \ if ((address & 0x0001FFFF) >= SIZE_VRAM) { \
LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \ if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \
} else { \ mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load32: 0x%08X", address); \
LOAD_32(value, address & 0x00017FFC, gba->video.vram); \ value = 0; \
break; \
} \ } \
address &= 0x00017FFC; \
} \
LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \
wait += waitstatesRegion[REGION_VRAM]; wait += waitstatesRegion[REGION_VRAM];
#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); #define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw);
@ -520,11 +524,15 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette);
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
LOAD_16(value, address & 0x0001FFFE, gba->video.vram); if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
} else { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load16: 0x%08X", address);
LOAD_16(value, address & 0x00017FFE, gba->video.vram); value = 0;
break;
} }
address &= 0x00017FFE;
}
LOAD_16(value, address & 0x0001FFFE, gba->video.vram);
break; break;
case REGION_OAM: case REGION_OAM:
LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw); LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw);
@ -631,11 +639,15 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)]; value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)];
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF]; if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
} else { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load8: 0x%08X", address);
value = ((uint8_t*) gba->video.vram)[address & 0x00017FFF]; value = 0;
break;
} }
address &= 0x00017FFF;
}
value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF];
break; break;
case REGION_OAM: case REGION_OAM:
value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)]; value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)];
@ -717,21 +729,19 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
wait += waitstatesRegion[REGION_PALETTE_RAM]; wait += waitstatesRegion[REGION_PALETTE_RAM];
#define STORE_VRAM \ #define STORE_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \ if ((address & 0x0001FFFF) >= SIZE_VRAM) { \
if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \
mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store32: 0x%08X", address); \
break; \
} \
address &= 0x00017FFC; \
} \
LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \ LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \
if (oldValue != value) { \ if (oldValue != value) { \
STORE_32(value, address & 0x0001FFFC, gba->video.vram); \ STORE_32(value, address & 0x0001FFFC, gba->video.vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \ gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
} \ } \
} else { \
LOAD_32(oldValue, address & 0x00017FFC, gba->video.vram); \
if (oldValue != value) { \
STORE_32(value, address & 0x00017FFC, gba->video.vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
} \
} \
wait += waitstatesRegion[REGION_VRAM]; wait += waitstatesRegion[REGION_VRAM];
#define STORE_OAM \ #define STORE_OAM \
@ -840,19 +850,18 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
} }
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store16: 0x%08X", address);
break;
}
address &= 0x00017FFE;
}
LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram); LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram);
if (value != oldValue) { if (value != oldValue) {
STORE_16(value, address & 0x0001FFFE, gba->video.vram); STORE_16(value, address & 0x0001FFFE, gba->video.vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
} }
} else {
LOAD_16(oldValue, address & 0x00017FFE, gba->video.vram);
if (value != oldValue) {
STORE_16(value, address & 0x00017FFE, gba->video.vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
}
}
break; break;
case REGION_OAM: case REGION_OAM:
LOAD_16(oldValue, address & (SIZE_OAM - 2), gba->video.oam.raw); LOAD_16(oldValue, address & (SIZE_OAM - 2), gba->video.oam.raw);
@ -939,7 +948,6 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) { if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) {
// TODO: check BG mode
mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
break; break;
} }