all repos — mgba @ 5bb811a16e32a8061319af6c772a941aad9bfaa1

mGBA Game Boy Advance Emulator

DS Slot-1: Improve savedata setup via IPC sniffing
Vicki Pfau vi@endrift.com
Wed, 12 Apr 2017 00:55:31 -0700
commit

5bb811a16e32a8061319af6c772a941aad9bfaa1

parent

9a35691a03d1dc9250208f2a7ab8cdc7fb8bf2aa

4 files changed, 72 insertions(+), 23 deletions(-)

jump to
M CHANGESCHANGES

@@ -2,6 +2,7 @@ medusa alpha 2: (Future)

Features: - DS Audio: Add PSG audio - DS Video: Add display capture blending + - DS Slot-1: Improve savedata setup via IPC sniffing Bugfixes: - DS Video: Fix VRAM mirroring in the renderer (fixes mgba.io/i/561) - DS Video: Fix extended modes 1.x screen base range (fixes mgba.io/i/568)
M include/mgba/internal/ds/slot1.hinclude/mgba/internal/ds/slot1.h

@@ -55,7 +55,7 @@ uint8_t spiCommand;

uint8_t statusReg; int spiAddressingRemaining; uint32_t spiAddress; - int32_t spiAddressingPc; + int spiAddressingBits; uint8_t* spiData; struct VFile* spiVf;

@@ -70,6 +70,7 @@

DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config); DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control); void DSSlot1WriteSPI(struct DSCommon* dscore, uint8_t datum); +void DSSlot1ConfigureSPI(struct DS* ds, uint32_t paramPtr); struct GBADMA; void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info);
M src/ds/ipc.csrc/ds/ipc.c

@@ -10,6 +10,16 @@ #include <mgba/internal/ds/io.h>

mLOG_DEFINE_CATEGORY(DS_IPC, "DS IPC", "ds.ipc"); +static void _parseIPC(struct DS* ds, uint32_t value) { + switch (value & 0x1F) { + case 0x0B: // Savedata + if (value & ~0x3F && ds->memory.slot1.savedataType == DS_SAVEDATA_AUTODETECT) { + DSSlot1ConfigureSPI(ds, value >> 6); + } + break; + } +} + void DSIPCWriteSYNC(struct ARMCore* remoteCpu, uint16_t* remoteIo, int16_t value) { remoteIo[DS_REG_IPCSYNC >> 1] &= 0xFFF0; remoteIo[DS_REG_IPCSYNC >> 1] |= (value >> 8) & 0x0F;

@@ -41,6 +51,9 @@ if (!DSIPCFIFOCNTIsEnable(dscore->memory.io[DS_REG_IPCFIFOCNT >> 1])) {

return; } mLOG(DS_IPC, DEBUG, "Written from ARM%c: %08X", (dscore == &dscore->p->ds7) ? '7' : '9', value); + if (!dscore->p->isHomebrew && dscore == &dscore->p->ds9) { + _parseIPC(dscore->p, value); + } CircleBufferWrite32(&dscore->ipc->fifo, value); size_t fullness = CircleBufferSize(&dscore->ipc->fifo); if (fullness == 4) {
M src/ds/slot1.csrc/ds/slot1.c

@@ -37,6 +37,7 @@ ds->memory.slot1.statusReg = 0;

ds->memory.slot1.spiCommand = 0; ds->memory.slot1.spiHoldEnabled = 0; ds->memory.slot1.dmaSource = -1; + ds->memory.slot1.spiAddressingBits = 16; } static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t cyclesLate) {

@@ -223,20 +224,8 @@ if (dscore->p->memory.slot1.spiAddressingRemaining) {

dscore->p->memory.slot1.spiAddress <<= 8; dscore->p->memory.slot1.spiAddress |= datum; dscore->p->memory.slot1.spiAddressingRemaining -= 8; - if (dscore->p->memory.slot1.spiAddressingPc >= 0) { - dscore->p->memory.slot1.spiAddressingPc = dscore->cpu->gprs[ARM_PC]; - } return 0xFF; - } else if (dscore->cpu->gprs[ARM_PC] == dscore->p->memory.slot1.spiAddressingPc) { - dscore->p->memory.slot1.spiAddress <<= 8; - dscore->p->memory.slot1.spiAddress |= datum; - dscore->p->memory.slot1.savedataType = DS_SAVEDATA_FLASH; - return 0xFF; - } else { - if (dscore->p->memory.slot1.spiAddress) { - // Cease autodetection - dscore->p->memory.slot1.spiAddressingPc = -1; - } + } else if (dscore->p->isHomebrew) { if (!_slot1GuaranteeSize(&dscore->p->memory.slot1)) { return 0xFF; }

@@ -253,6 +242,29 @@ }

return 0xFF; } +static uint8_t _slot1SPIEEPROM(struct DSCommon* dscore, uint8_t datum) { + DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1]; + + if (dscore->p->memory.slot1.spiAddressingRemaining) { + dscore->p->memory.slot1.spiAddress <<= 8; + dscore->p->memory.slot1.spiAddress |= datum; + dscore->p->memory.slot1.spiAddressingRemaining -= 8; + return 0xFF; + } + + switch (dscore->p->memory.slot1.spiCommand) { + case 0x03: // RDLO + case 0x0B: // RDHI + return dscore->p->memory.slot1.spiData[dscore->p->memory.slot1.spiAddress++]; + case 0x02: // WRLO + case 0x0A: // WRHI + dscore->p->memory.slot1.spiData[dscore->p->memory.slot1.spiAddress] = datum; + ++dscore->p->memory.slot1.spiAddress; + break; + } + return 0xFF; +} + static uint8_t _slot1SPIFlash(struct DSCommon* dscore, uint8_t datum) { DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1];

@@ -261,7 +273,7 @@ dscore->p->memory.slot1.spiAddress <<= 8;

dscore->p->memory.slot1.spiAddress |= datum; dscore->p->memory.slot1.spiAddressingRemaining -= 8; return 0xFF; - } else { + } else if (dscore->p->isHomebrew) { if (!_slot1GuaranteeSize(&dscore->p->memory.slot1)) { return 0xFF; }

@@ -303,15 +315,12 @@ // Probably RDHI

if (oldValue == 0x0B && dscore->p->memory.slot1.savedataType == DS_SAVEDATA_AUTODETECT) { dscore->p->memory.slot1.savedataType = DS_SAVEDATA_EEPROM512; } - dscore->p->memory.slot1.spiAddress = 0; - switch (dscore->p->memory.slot1.savedataType) { - case DS_SAVEDATA_FLASH: - dscore->p->memory.slot1.spiAddressingRemaining = 24; - break; - default: - dscore->p->memory.slot1.spiAddressingRemaining = 16; - break; + if ((oldValue & 0x08) && dscore->p->memory.slot1.savedataType == DS_SAVEDATA_EEPROM512) { + dscore->p->memory.slot1.spiAddress = 1; + } else { + dscore->p->memory.slot1.spiAddress = 0; } + dscore->p->memory.slot1.spiAddressingRemaining = dscore->p->memory.slot1.spiAddressingBits; } else { switch (dscore->p->memory.slot1.spiCommand) { case 0x04: // WRDI

@@ -330,6 +339,10 @@ newValue = _slot1SPIAutodetect(dscore, oldValue);

break; case DS_SAVEDATA_FLASH: newValue = _slot1SPIFlash(dscore, oldValue); + break; + case DS_SAVEDATA_EEPROM: + case DS_SAVEDATA_EEPROM512: + newValue = _slot1SPIEEPROM(dscore, oldValue); break; default: mLOG(DS_SLOT1, STUB, "Unimplemented SPI write: %04X:%02X", control, oldValue);

@@ -378,6 +391,27 @@ if (!slot1->spiData) {

slot1->spiData = slot1->spiVf->map(slot1->spiVf, slot1->spiVf->size(slot1->spiVf), MAP_WRITE); } return slot1->spiData; +} + +void DSSlot1ConfigureSPI(struct DS* ds, uint32_t paramPtr) { + struct ARMCore* cpu = ds->ds7.cpu; + uint32_t saveParams = cpu->memory.load32(cpu, paramPtr + 4, NULL); + uint32_t size = 1 << ((saveParams & 0xFF00) >> 8); + if ((saveParams & 0xFF) == 2) { + ds->memory.slot1.savedataType = DS_SAVEDATA_FLASH; + } else { + ds->memory.slot1.savedataType = DS_SAVEDATA_EEPROM; + } + if (size >= 0x10000) { + ds->memory.slot1.spiAddressingBits = 24; + } else if (size <= 0x200) { + ds->memory.slot1.spiAddressingBits = 8; + ds->memory.slot1.savedataType = DS_SAVEDATA_EEPROM512; + } else { + ds->memory.slot1.spiAddressingBits = 16; + } + ds->memory.slot1.spiAddress = size; + _slot1GuaranteeSize(&ds->memory.slot1); } void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info) {