mirror of https://github.com/mgba-emu/mgba.git
DS Slot-1: Improve savedata setup via IPC sniffing
This commit is contained in:
parent
9a35691a03
commit
5bb811a16e
1
CHANGES
1
CHANGES
|
@ -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)
|
||||
|
|
|
@ -55,7 +55,7 @@ struct DSSlot1 {
|
|||
uint8_t statusReg;
|
||||
int spiAddressingRemaining;
|
||||
uint32_t spiAddress;
|
||||
int32_t spiAddressingPc;
|
||||
int spiAddressingBits;
|
||||
|
||||
uint8_t* spiData;
|
||||
struct VFile* spiVf;
|
||||
|
@ -70,6 +70,7 @@ void DSSlot1Reset(struct DS* ds);
|
|||
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);
|
||||
|
|
13
src/ds/ipc.c
13
src/ds/ipc.c
|
@ -10,6 +10,16 @@
|
|||
|
||||
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 @@ void DSIPCWriteFIFO(struct DSCommon* dscore, int32_t value) {
|
|||
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) {
|
||||
|
|
|
@ -37,6 +37,7 @@ void DSSlot1Reset(struct DS* ds) {
|
|||
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 @@ static uint8_t _slot1SPIAutodetect(struct DSCommon* dscore, uint8_t datum) {
|
|||
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 @@ static uint8_t _slot1SPIAutodetect(struct DSCommon* dscore, uint8_t datum) {
|
|||
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 @@ static uint8_t _slot1SPIFlash(struct DSCommon* dscore, uint8_t datum) {
|
|||
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 @@ static void _slot1SPI(struct mTiming* timing, void* context, uint32_t cyclesLate
|
|||
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
|
||||
|
@ -331,6 +340,10 @@ static void _slot1SPI(struct mTiming* timing, void* context, uint32_t cyclesLate
|
|||
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);
|
||||
break;
|
||||
|
@ -380,6 +393,27 @@ static bool _slot1GuaranteeSize(struct DSSlot1* slot1) {
|
|||
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) {
|
||||
UNUSED(info);
|
||||
dscore->p->memory.slot1.dmaSource = number;
|
||||
|
|
Loading…
Reference in New Issue