DS Slot-1: A little work on savegames
Vicki Pfau vi@endrift.com
Wed, 22 Feb 2017 22:34:06 -0800
5 files changed,
67 insertions(+),
5 deletions(-)
M
include/mgba/internal/ds/ds.h
→
include/mgba/internal/ds/ds.h
@@ -155,6 +155,7 @@ void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger);
void DSDetachDebugger(struct DS* ds); bool DSLoadROM(struct DS* ds, struct VFile* vf); +bool DSLoadSave(struct DS* ds, struct VFile* vf); void DSUnloadROM(struct DS* ds); void DSApplyPatch(struct DS* ds, struct Patch* patch);
M
include/mgba/internal/ds/slot1.h
→
include/mgba/internal/ds/slot1.h
@@ -36,6 +36,7 @@ DS_SAVEDATA_EEPROM = 2,
DS_SAVEDATA_FLASH = 3 }; +struct VFile; struct DSSlot1 { uint8_t command[8]; uint32_t address;@@ -48,10 +49,17 @@ struct mTimingEvent spiEvent;
bool spiHoldEnabled; uint8_t spiCommand; uint8_t statusReg; + int spiAddressingRemaining; + uint32_t spiAddress; + + uint8_t* spiData; + struct VFile* spiVf; + struct VFile* spiRealVf; }; struct DS; struct DSCommon; +void DSSlot1SPIInit(struct DS* ds, struct VFile* vf); void DSSlot1Reset(struct DS* ds); DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config); DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control);
M
src/ds/core.c
→
src/ds/core.c
@@ -163,7 +163,7 @@ return DSLoadBIOS(core->board, vf);
} static bool _DSCoreLoadSave(struct mCore* core, struct VFile* vf) { - return false; + return DSLoadSave(core->board, vf); } static bool _DSCoreLoadPatch(struct mCore* core, struct VFile* vf) {
M
src/ds/ds.c
→
src/ds/ds.c
@@ -201,6 +201,7 @@ ds->rtcSource = NULL;
ds->rumble = NULL; ds->romVf = NULL; + DSSlot1SPIInit(ds, NULL); ds->keyCallback = NULL;@@ -441,6 +442,11 @@ bool DSLoadROM(struct DS* ds, struct VFile* vf) {
DSUnloadROM(ds); ds->romVf = vf; // TODO: error check + return true; +} + +bool DSLoadSave(struct DS* ds, struct VFile* sav) { + DSSlot1SPIInit(ds, sav); return true; }
M
src/ds/slot1.c
→
src/ds/slot1.c
@@ -7,17 +7,26 @@ #include <mgba/internal/ds/slot1.h>
#include <mgba/internal/arm/macros.h> #include <mgba/internal/ds/ds.h> +#include <mgba-util/math.h> #include <mgba-util/vfs.h> mLOG_DEFINE_CATEGORY(DS_SLOT1, "DS Slot-1"); static void _slot1SPI(struct mTiming*, void* context, uint32_t cyclesLate); +static bool _slot1GuaranteeSize(struct DSSlot1*); -void DSSlot1Reset(struct DS* ds) { +void DSSlot1SPIInit(struct DS* ds, struct VFile* vf) { ds->memory.slot1.spiEvent.name = "DS Slot-1 SPI"; ds->memory.slot1.spiEvent.priority = 0x70; ds->memory.slot1.spiEvent.context = NULL; ds->memory.slot1.spiEvent.callback = _slot1SPI; + ds->memory.slot1.savedataType = DS_SAVEDATA_AUTODETECT; + ds->memory.slot1.spiVf = vf; + ds->memory.slot1.spiRealVf = vf; + ds->memory.slot1.spiData = NULL; +} + +void DSSlot1Reset(struct DS* ds) { ds->memory.slot1.statusReg = 0; ds->memory.slot1.spiCommand = 0; ds->memory.slot1.spiHoldEnabled = 0;@@ -132,6 +141,26 @@
static uint8_t _slot1SPIAutodetect(struct DSCommon* dscore, uint8_t datum) { DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1]; mLOG(DS_SLOT1, STUB, "Unimplemented SPI write: %04X:%02X:%02X", control, dscore->p->memory.slot1.spiCommand, datum); + + 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; + } else { + if (!_slot1GuaranteeSize(&dscore->p->memory.slot1)) { + return 0xFF; + } + } + + switch (dscore->p->memory.slot1.spiCommand) { + case 0x03: // RD + return dscore->p->memory.slot1.spiData[dscore->p->memory.slot1.spiAddress++]; + case 0x02: // WR + dscore->p->memory.slot1.spiData[dscore->p->memory.slot1.spiAddress] = datum; + ++dscore->p->memory.slot1.spiAddress; + break; + } return 0xFF; }@@ -141,7 +170,7 @@ UNUSED(cyclesLate);
struct DSCommon* dscore = context; DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1]; uint8_t oldValue = dscore->memory.io[DS_REG_AUXSPIDATA >> 1]; - uint8_t newValue = 0; + uint8_t newValue = 0xFF; if (!dscore->p->memory.slot1.spiCommand) { dscore->p->memory.slot1.spiCommand = oldValue;@@ -149,6 +178,8 @@ // 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; + dscore->p->memory.slot1.spiAddressingRemaining = 16; } else { switch (dscore->p->memory.slot1.spiCommand) { case 0x04: // WRDI@@ -177,7 +208,23 @@ dscore->memory.io[DS_REG_AUXSPIDATA >> 1] = newValue;
dscore->ipc->memory.io[DS_REG_AUXSPIDATA >> 1] = newValue; dscore->memory.io[DS_REG_AUXSPICNT >> 1] = control; dscore->ipc->memory.io[DS_REG_AUXSPICNT >> 1] = control; - if (DSSlot1AUXSPICNTIsDoIRQ(control)) { - DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_SLOT1); +} + +static bool _slot1GuaranteeSize(struct DSSlot1* slot1) { + if (!slot1->spiVf) { + return false; } + if (slot1->spiAddress >= slot1->spiVf->size(slot1->spiVf)) { + size_t size = toPow2(slot1->spiAddress + 1); + if (slot1->spiData) { + slot1->spiVf->unmap(slot1->spiVf, slot1->spiData, slot1->spiVf->size(slot1->spiVf)); + slot1->spiData = NULL; + } + slot1->spiVf->truncate(slot1->spiVf, size); + // TODO: Write FFs + } + if (!slot1->spiData) { + slot1->spiData = slot1->spiVf->map(slot1->spiVf, slot1->spiVf->size(slot1->spiVf), MAP_WRITE); + } + return slot1->spiData; }