mirror of https://github.com/mgba-emu/mgba.git
DS Slot-1: A little work on savegames
This commit is contained in:
parent
a557fb6ca6
commit
a60f3592d1
|
@ -155,6 +155,7 @@ void DSAttachDebugger(struct DS* ds, struct mDebugger* debugger);
|
||||||
void DSDetachDebugger(struct DS* ds);
|
void DSDetachDebugger(struct DS* ds);
|
||||||
|
|
||||||
bool DSLoadROM(struct DS* ds, struct VFile* vf);
|
bool DSLoadROM(struct DS* ds, struct VFile* vf);
|
||||||
|
bool DSLoadSave(struct DS* ds, struct VFile* vf);
|
||||||
void DSUnloadROM(struct DS* ds);
|
void DSUnloadROM(struct DS* ds);
|
||||||
void DSApplyPatch(struct DS* ds, struct Patch* patch);
|
void DSApplyPatch(struct DS* ds, struct Patch* patch);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ enum DSSavedataType {
|
||||||
DS_SAVEDATA_FLASH = 3
|
DS_SAVEDATA_FLASH = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VFile;
|
||||||
struct DSSlot1 {
|
struct DSSlot1 {
|
||||||
uint8_t command[8];
|
uint8_t command[8];
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
@ -48,10 +49,17 @@ struct DSSlot1 {
|
||||||
bool spiHoldEnabled;
|
bool spiHoldEnabled;
|
||||||
uint8_t spiCommand;
|
uint8_t spiCommand;
|
||||||
uint8_t statusReg;
|
uint8_t statusReg;
|
||||||
|
int spiAddressingRemaining;
|
||||||
|
uint32_t spiAddress;
|
||||||
|
|
||||||
|
uint8_t* spiData;
|
||||||
|
struct VFile* spiVf;
|
||||||
|
struct VFile* spiRealVf;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DS;
|
struct DS;
|
||||||
struct DSCommon;
|
struct DSCommon;
|
||||||
|
void DSSlot1SPIInit(struct DS* ds, struct VFile* vf);
|
||||||
void DSSlot1Reset(struct DS* ds);
|
void DSSlot1Reset(struct DS* ds);
|
||||||
DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config);
|
DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config);
|
||||||
DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control);
|
DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control);
|
||||||
|
|
|
@ -163,7 +163,7 @@ static bool _DSCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _DSCoreLoadSave(struct mCore* core, struct VFile* 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) {
|
static bool _DSCoreLoadPatch(struct mCore* core, struct VFile* vf) {
|
||||||
|
|
|
@ -201,6 +201,7 @@ static void DSInit(void* cpu, struct mCPUComponent* component) {
|
||||||
ds->rumble = NULL;
|
ds->rumble = NULL;
|
||||||
|
|
||||||
ds->romVf = NULL;
|
ds->romVf = NULL;
|
||||||
|
DSSlot1SPIInit(ds, NULL);
|
||||||
|
|
||||||
ds->keyCallback = NULL;
|
ds->keyCallback = NULL;
|
||||||
|
|
||||||
|
@ -444,6 +445,11 @@ bool DSLoadROM(struct DS* ds, struct VFile* vf) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DSLoadSave(struct DS* ds, struct VFile* sav) {
|
||||||
|
DSSlot1SPIInit(ds, sav);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DSIsROM(struct VFile* vf) {
|
bool DSIsROM(struct VFile* vf) {
|
||||||
if (vf->seek(vf, DS_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
|
if (vf->seek(vf, DS_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -7,17 +7,26 @@
|
||||||
|
|
||||||
#include <mgba/internal/arm/macros.h>
|
#include <mgba/internal/arm/macros.h>
|
||||||
#include <mgba/internal/ds/ds.h>
|
#include <mgba/internal/ds/ds.h>
|
||||||
|
#include <mgba-util/math.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
mLOG_DEFINE_CATEGORY(DS_SLOT1, "DS Slot-1");
|
mLOG_DEFINE_CATEGORY(DS_SLOT1, "DS Slot-1");
|
||||||
|
|
||||||
static void _slot1SPI(struct mTiming*, void* context, uint32_t cyclesLate);
|
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.name = "DS Slot-1 SPI";
|
||||||
ds->memory.slot1.spiEvent.priority = 0x70;
|
ds->memory.slot1.spiEvent.priority = 0x70;
|
||||||
ds->memory.slot1.spiEvent.context = NULL;
|
ds->memory.slot1.spiEvent.context = NULL;
|
||||||
ds->memory.slot1.spiEvent.callback = _slot1SPI;
|
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.statusReg = 0;
|
||||||
ds->memory.slot1.spiCommand = 0;
|
ds->memory.slot1.spiCommand = 0;
|
||||||
ds->memory.slot1.spiHoldEnabled = 0;
|
ds->memory.slot1.spiHoldEnabled = 0;
|
||||||
|
@ -132,6 +141,26 @@ void DSSlot1WriteSPI(struct DSCommon* dscore, uint8_t datum) {
|
||||||
static uint8_t _slot1SPIAutodetect(struct DSCommon* dscore, uint8_t datum) {
|
static uint8_t _slot1SPIAutodetect(struct DSCommon* dscore, uint8_t datum) {
|
||||||
DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1];
|
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);
|
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;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +170,7 @@ static void _slot1SPI(struct mTiming* timing, void* context, uint32_t cyclesLate
|
||||||
struct DSCommon* dscore = context;
|
struct DSCommon* dscore = context;
|
||||||
DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1];
|
DSSlot1AUXSPICNT control = dscore->memory.io[DS_REG_AUXSPICNT >> 1];
|
||||||
uint8_t oldValue = dscore->memory.io[DS_REG_AUXSPIDATA >> 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) {
|
if (!dscore->p->memory.slot1.spiCommand) {
|
||||||
dscore->p->memory.slot1.spiCommand = oldValue;
|
dscore->p->memory.slot1.spiCommand = oldValue;
|
||||||
|
@ -149,6 +178,8 @@ static void _slot1SPI(struct mTiming* timing, void* context, uint32_t cyclesLate
|
||||||
if (oldValue == 0x0B && dscore->p->memory.slot1.savedataType == DS_SAVEDATA_AUTODETECT) {
|
if (oldValue == 0x0B && dscore->p->memory.slot1.savedataType == DS_SAVEDATA_AUTODETECT) {
|
||||||
dscore->p->memory.slot1.savedataType = DS_SAVEDATA_EEPROM512;
|
dscore->p->memory.slot1.savedataType = DS_SAVEDATA_EEPROM512;
|
||||||
}
|
}
|
||||||
|
dscore->p->memory.slot1.spiAddress = 0;
|
||||||
|
dscore->p->memory.slot1.spiAddressingRemaining = 16;
|
||||||
} else {
|
} else {
|
||||||
switch (dscore->p->memory.slot1.spiCommand) {
|
switch (dscore->p->memory.slot1.spiCommand) {
|
||||||
case 0x04: // WRDI
|
case 0x04: // WRDI
|
||||||
|
@ -177,7 +208,23 @@ static void _slot1SPI(struct mTiming* timing, void* context, uint32_t cyclesLate
|
||||||
dscore->ipc->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->memory.io[DS_REG_AUXSPICNT >> 1] = control;
|
||||||
dscore->ipc->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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue