GBA Memory: Improve robustness of Matrix memory support
Vicki Pfau vi@endrift.com
Thu, 27 Aug 2020 04:27:13 -0700
5 files changed,
89 insertions(+),
9 deletions(-)
M
CHANGES
→
CHANGES
@@ -33,6 +33,7 @@ - GBA DMA: Fix ordering and timing of overlapping DMAs
- GBA Hardware: Fix GB Player detection on big endian platforms - GBA Memory: Improve gamepak prefetch timing - GBA Memory: Stall on VRAM access in mode 2 (fixes mgba.io/i/190) + - GBA Memory: Improve robustness of Matrix memory support - GBA SIO: Fix copying Normal mode transfer values - GBA SIO: Fix Normal mode being totally broken (fixes mgba.io/i/1800) - GBA SIO: Fix deseralizing SIO registers
M
include/mgba/internal/gba/matrix.h
→
include/mgba/internal/gba/matrix.h
@@ -10,18 +10,25 @@ #include <mgba-util/common.h>
CXX_GUARD_START +#define GBA_MATRIX_MAPPINGS_MAX 16 + struct GBAMatrix { uint32_t cmd; uint32_t paddr; uint32_t vaddr; uint32_t size; + + uint32_t mappings[GBA_MATRIX_MAPPINGS_MAX]; }; struct GBA; -struct GBAMemory; void GBAMatrixReset(struct GBA*); void GBAMatrixWrite(struct GBA*, uint32_t address, uint32_t value); void GBAMatrixWrite16(struct GBA*, uint32_t address, uint16_t value); + +struct GBASerializedState; +void GBAMatrixSerialize(const struct GBA* memory, struct GBASerializedState* state); +void GBAMatrixDeserialize(struct GBA* memory, const struct GBASerializedState* state); CXX_GUARD_END
M
include/mgba/internal/gba/serialize.h
→
include/mgba/internal/gba/serialize.h
@@ -331,7 +331,12 @@
uint32_t dmaTransferRegister; uint32_t dmaBlockPC; - uint32_t reservedHardware[4]; + struct { + uint32_t cmd; + uint32_t paddr; + uint32_t vaddr; + uint32_t size; + } matrix; struct { uint8_t type;@@ -356,7 +361,9 @@ GBASerializedMiscFlags miscFlags;
uint32_t nextIrq; int32_t biosStall; - uint32_t reserved[54]; + uint32_t matrixMappings[16]; + + uint32_t reserved[38]; uint16_t io[SIZE_IO >> 1]; uint16_t pram[SIZE_PALETTE_RAM >> 1];
M
src/gba/matrix.c
→
src/gba/matrix.c
@@ -8,26 +8,43 @@
#include <mgba/internal/arm/macros.h> #include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/memory.h> +#include <mgba/internal/gba/serialize.h> #include <mgba-util/vfs.h> static void _remapMatrix(struct GBA* gba) { + if (gba->memory.matrix.vaddr & 0xFFFFE1FF) { + mLOG(GBA_MEM, ERROR, "Invalid Matrix mapping: %08X", gba->memory.matrix.vaddr); + return; + } + if (gba->memory.matrix.size & 0xFFFFE1FF) { + mLOG(GBA_MEM, ERROR, "Invalid Matrix size: %08X", gba->memory.matrix.size); + return; + } + if ((gba->memory.matrix.vaddr + gba->memory.matrix.size - 1) & 0xFFFFE000) { + mLOG(GBA_MEM, ERROR, "Invalid Matrix mapping end: %08X", gba->memory.matrix.vaddr + gba->memory.matrix.size); + return; + } + int start = (gba->memory.matrix.vaddr >> 9) & 0x1F; + int size = (gba->memory.matrix.size >> 9) & 0x1F; + int i; + for (i = 0; i < size; ++i) { + gba->memory.matrix.mappings[start + i] = gba->memory.matrix.paddr + (i << 9); + } + gba->romVf->seek(gba->romVf, gba->memory.matrix.paddr, SEEK_SET); gba->romVf->read(gba->romVf, &gba->memory.rom[gba->memory.matrix.vaddr >> 2], gba->memory.matrix.size); } void GBAMatrixReset(struct GBA* gba) { - gba->memory.matrix.paddr = 0x200; + memset(gba->memory.matrix.mappings, 0, sizeof(gba->memory.matrix.mappings)); gba->memory.matrix.size = 0x1000; + gba->memory.matrix.paddr = 0; gba->memory.matrix.vaddr = 0; _remapMatrix(gba); + gba->memory.matrix.paddr = 0x200; gba->memory.matrix.vaddr = 0x1000; _remapMatrix(gba); - - gba->memory.matrix.paddr = 0; - gba->memory.matrix.vaddr = 0; - gba->memory.matrix.size = 0x100; - _remapMatrix(gba); } void GBAMatrixWrite(struct GBA* gba, uint32_t address, uint32_t value) {@@ -51,6 +68,10 @@ case 0x8:
gba->memory.matrix.vaddr = value & 0x007FFFFF; return; case 0xC: + if (value == 0) { + mLOG(GBA_MEM, ERROR, "Rejecting Matrix write for size 0"); + return; + } gba->memory.matrix.size = value << 9; return; }@@ -73,3 +94,39 @@ GBAMatrixWrite(gba, address, value | (gba->memory.matrix.size & 0xFFFF0000));
break; } } + +void GBAMatrixSerialize(const struct GBA* gba, struct GBASerializedState* state) { + STORE_32(gba->memory.matrix.cmd, 0, &state->matrix.cmd); + STORE_32(gba->memory.matrix.paddr, 0, &state->matrix.paddr); + STORE_32(gba->memory.matrix.vaddr, 0, &state->matrix.vaddr); + STORE_32(gba->memory.matrix.size, 0, &state->matrix.size); + + if (GBA_MATRIX_MAPPINGS_MAX != 16) { + mLOG(GBA_MEM, ERROR, "Matrix memory serialization is broken!"); + } + + int i; + for (i = 0; i < 16; ++i) { + STORE_32(gba->memory.matrix.mappings[i], i << 2, state->matrixMappings); + } +} + +void GBAMatrixDeserialize(struct GBA* gba, const struct GBASerializedState* state) { + if (GBA_MATRIX_MAPPINGS_MAX != 16) { + mLOG(GBA_MEM, ERROR, "Matrix memory deserialization is broken!"); + } + gba->memory.matrix.size = 0x200; + + int i; + for (i = 0; i < 16; ++i) { + LOAD_32(gba->memory.matrix.mappings[i], i << 2, state->matrixMappings); + gba->memory.matrix.paddr = gba->memory.matrix.mappings[i]; + gba->memory.matrix.vaddr = i << 9; + _remapMatrix(gba); + } + + LOAD_32(gba->memory.matrix.cmd, 0, &state->matrix.cmd); + LOAD_32(gba->memory.matrix.paddr, 0, &state->matrix.paddr); + LOAD_32(gba->memory.matrix.vaddr, 0, &state->matrix.vaddr); + LOAD_32(gba->memory.matrix.size, 0, &state->matrix.size); +}
M
src/gba/serialize.c
→
src/gba/serialize.c
@@ -76,6 +76,10 @@ GBAIOSerialize(gba, state);
GBAVideoSerialize(&gba->video, state); GBAAudioSerialize(&gba->audio, state); GBASavedataSerialize(&gba->memory.savedata, state); + + if (gba->memory.matrix.size) { + GBAMatrixSerialize(gba, state); + } } bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {@@ -195,6 +199,10 @@ GBAMemoryDeserialize(&gba->memory, state);
GBAIODeserialize(gba, state); GBAAudioDeserialize(&gba->audio, state); GBASavedataDeserialize(&gba->memory.savedata, state); + + if (gba->memory.matrix.size) { + GBAMatrixDeserialize(gba, state); + } gba->timing.reroot = gba->timing.root; gba->timing.root = NULL;