all repos — mgba @ a60f3592d1554b22de48373a3a0b075d8a8d4202

mGBA Game Boy Advance Emulator

DS Slot-1: A little work on savegames
Vicki Pfau vi@endrift.com
Wed, 22 Feb 2017 22:34:06 -0800
commit

a60f3592d1554b22de48373a3a0b075d8a8d4202

parent

a557fb6ca67b023be01e306a69a2f3e1c79ab79a

M include/mgba/internal/ds/ds.hinclude/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.hinclude/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.csrc/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.csrc/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.csrc/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; }