GBA Memory: Improve robustness of Matrix memory support

This commit is contained in:
Vicki Pfau 2020-08-27 04:27:13 -07:00
parent 6e01765ed2
commit 65fb61d7e2
5 changed files with 90 additions and 10 deletions

View File

@ -33,6 +33,7 @@ Emulation fixes:
- 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

View File

@ -10,19 +10,26 @@
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
#endif

View File

@ -331,7 +331,12 @@ struct GBASerializedState {
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 @@ struct GBASerializedState {
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];

View File

@ -8,25 +8,42 @@
#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.vaddr = 0;
_remapMatrix(gba);
gba->memory.matrix.vaddr = 0x1000;
_remapMatrix(gba);
gba->memory.matrix.paddr = 0;
gba->memory.matrix.vaddr = 0;
gba->memory.matrix.size = 0x100;
_remapMatrix(gba);
gba->memory.matrix.paddr = 0x200;
gba->memory.matrix.vaddr = 0x1000;
_remapMatrix(gba);
}
@ -51,6 +68,10 @@ void GBAMatrixWrite(struct GBA* gba, uint32_t address, uint32_t value) {
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 @@ void GBAMatrixWrite16(struct GBA* gba, uint32_t address, uint16_t value) {
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);
}

View File

@ -76,6 +76,10 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* 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) {
@ -196,6 +200,10 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* 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;