mirror of https://github.com/mgba-emu/mgba.git
DS SPI: Implement firmware access
This commit is contained in:
parent
b77716738a
commit
5c3fc0ac0d
|
@ -49,14 +49,18 @@ enum {
|
|||
struct DSSPIBus {
|
||||
bool holdEnabled;
|
||||
|
||||
uint8_t firmwareMode;
|
||||
uint8_t firmCommand;
|
||||
uint8_t firmStatusReg;
|
||||
int firmAddressingRemaining;
|
||||
uint32_t firmAddress;
|
||||
|
||||
struct mTimingEvent tscEvent;
|
||||
uint8_t tscControlByte;
|
||||
uint16_t tscRegister;
|
||||
int tscOffset;
|
||||
|
||||
uint8_t powmgrByte;
|
||||
|
||||
struct mTimingEvent event;
|
||||
};
|
||||
|
||||
struct DS;
|
||||
|
|
71
src/ds/spi.c
71
src/ds/spi.c
|
@ -6,23 +6,26 @@
|
|||
#include <mgba/internal/ds/spi.h>
|
||||
|
||||
#include <mgba/internal/ds/ds.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
mLOG_DEFINE_CATEGORY(DS_SPI, "DS SPI");
|
||||
|
||||
static void _tscEvent(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||
static void _firmwareEvent(struct mTiming* timing, void* context, uint32_t cyclesLate);
|
||||
|
||||
void DSSPIReset(struct DS* ds) {
|
||||
memset(&ds->memory.spiBus, 0, sizeof(ds->memory.spiBus));
|
||||
ds->memory.spiBus.tscEvent.name = "DS SPI TSC";
|
||||
ds->memory.spiBus.tscEvent.context = ds;
|
||||
ds->memory.spiBus.tscEvent.callback = _tscEvent;
|
||||
ds->memory.spiBus.tscEvent.priority = 0x60;
|
||||
ds->memory.spiBus.event.name = "DS SPI Event";
|
||||
ds->memory.spiBus.event.context = ds;
|
||||
ds->memory.spiBus.event.callback = _tscEvent;
|
||||
ds->memory.spiBus.event.priority = 0x60;
|
||||
}
|
||||
|
||||
DSSPICNT DSSPIWriteControl(struct DS* ds, uint16_t control) {
|
||||
// TODO
|
||||
if (!ds->memory.spiBus.holdEnabled) {
|
||||
ds->memory.spiBus.tscControlByte = 0;
|
||||
ds->memory.spiBus.firmCommand = 0;
|
||||
}
|
||||
ds->memory.spiBus.holdEnabled = DSSPICNTIsCSHold(control);
|
||||
return control;
|
||||
|
@ -37,16 +40,19 @@ void DSSPIWrite(struct DS* ds, uint8_t datum) {
|
|||
baud = DS_ARM7TDMI_FREQUENCY >> baud;
|
||||
switch (DSSPICNTGetChipSelect(control)) {
|
||||
case DS_SPI_DEV_TSC:
|
||||
control = DSSPICNTFillBusy(control);
|
||||
mTimingDeschedule(&ds->ds7.timing, &ds->memory.spiBus.tscEvent);
|
||||
mTimingSchedule(&ds->ds7.timing, &ds->memory.spiBus.tscEvent, baud);
|
||||
ds->memory.spiBus.event.callback = _tscEvent;
|
||||
break;
|
||||
case DS_SPI_DEV_FIRMWARE:
|
||||
ds->memory.spiBus.event.callback = _firmwareEvent;
|
||||
break;
|
||||
case DS_SPI_DEV_POWERMAN:
|
||||
case DS_SPI_DEV_FIRMWARE:
|
||||
default:
|
||||
mLOG(DS_SPI, STUB, "Unimplemented data write: %04X:%02X", control, datum);
|
||||
break;
|
||||
}
|
||||
control = DSSPICNTFillBusy(control);
|
||||
mTimingDeschedule(&ds->ds7.timing, &ds->memory.spiBus.event);
|
||||
mTimingSchedule(&ds->ds7.timing, &ds->memory.spiBus.event, baud);
|
||||
ds->memory.io7[DS7_REG_SPICNT >> 1] = control;
|
||||
}
|
||||
|
||||
|
@ -102,3 +108,52 @@ static void _tscEvent(struct mTiming* timing, void* context, uint32_t cyclesLate
|
|||
DSRaiseIRQ(ds->ds7.cpu, ds->ds7.memory.io, DS_IRQ_SPI);
|
||||
}
|
||||
}
|
||||
|
||||
static void _firmwareEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
UNUSED(timing);
|
||||
UNUSED(cyclesLate);
|
||||
struct DS* ds = context;
|
||||
uint8_t oldValue = ds->memory.io7[DS7_REG_SPIDATA >> 1];
|
||||
DSSPICNT control = ds->memory.io7[DS7_REG_SPICNT >> 1];
|
||||
uint8_t newValue = 0;
|
||||
|
||||
if (!ds->memory.spiBus.firmCommand) {
|
||||
ds->memory.spiBus.firmCommand = oldValue;
|
||||
ds->memory.spiBus.firmAddress = 0;
|
||||
ds->memory.spiBus.firmAddressingRemaining = 24;
|
||||
} else if (ds->memory.spiBus.firmAddressingRemaining) {
|
||||
ds->memory.spiBus.firmAddress <<= 8;
|
||||
ds->memory.spiBus.firmAddress |= oldValue;
|
||||
ds->memory.spiBus.firmAddressingRemaining -= 8;
|
||||
ds->firmwareVf->seek(ds->firmwareVf, ds->memory.spiBus.firmAddress, SEEK_SET);
|
||||
} else {
|
||||
switch (ds->memory.spiBus.firmCommand) {
|
||||
case 0x02: // WR
|
||||
ds->firmwareVf->write(ds->firmwareVf, &oldValue, 1);
|
||||
++ds->memory.spiBus.firmAddress;
|
||||
break;
|
||||
case 0x03: // RD
|
||||
ds->firmwareVf->read(ds->firmwareVf, &newValue, 1);
|
||||
++ds->memory.spiBus.firmAddress;
|
||||
case 0x04: // WRDI
|
||||
ds->memory.spiBus.firmStatusReg &= ~2;
|
||||
break;
|
||||
case 0x05: // RDSR
|
||||
newValue = ds->memory.spiBus.firmStatusReg;
|
||||
break;
|
||||
case 0x06: // WREN
|
||||
ds->memory.spiBus.firmStatusReg |= 2;
|
||||
break;
|
||||
default:
|
||||
mLOG(DS_SPI, STUB, "Unimplemented Firmware write: %04X:%02X:%02X", control, ds->memory.spiBus.firmCommand, newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
control = DSSPICNTClearBusy(control);
|
||||
ds->memory.io7[DS7_REG_SPIDATA >> 1] = newValue;
|
||||
ds->memory.io7[DS7_REG_SPICNT >> 1] = control;
|
||||
if (DSSPICNTIsDoIRQ(control)) {
|
||||
DSRaiseIRQ(ds->ds7.cpu, ds->ds7.memory.io, DS_IRQ_SPI);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue