DS SPI: Add TSC stub
Vicki Pfau vi@endrift.com
Wed, 22 Feb 2017 16:43:44 -0800
5 files changed,
121 insertions(+),
4 deletions(-)
M
include/mgba/internal/ds/memory.h
→
include/mgba/internal/ds/memory.h
@@ -16,6 +16,7 @@ #include <mgba/internal/arm/arm.h>
#include <mgba/internal/ds/dma.h> #include <mgba/internal/ds/io.h> #include <mgba/internal/ds/slot1.h> +#include <mgba/internal/ds/spi.h> enum DSMemoryRegion { DS7_REGION_BIOS = 0x0,@@ -86,6 +87,7 @@ uint32_t* rom;
uint16_t io7[DS7_REG_MAX >> 1]; uint16_t io9[DS9_REG_MAX >> 1]; struct DSSlot1 slot1; + struct DSSPIBus spiBus; uint16_t vramMirror[9][0x40]; uint16_t vramMode[9][8];
M
include/mgba/internal/ds/spi.h
→
include/mgba/internal/ds/spi.h
@@ -11,6 +11,7 @@
CXX_GUARD_START #include <mgba/core/log.h> +#include <mgba/core/timing.h> mLOG_DECLARE_CATEGORY(DS_SPI);@@ -23,13 +24,43 @@ DECL_BIT(DSSPICNT, CSHold, 11);
DECL_BIT(DSSPICNT, DoIRQ, 14); DECL_BIT(DSSPICNT, Enable, 15); +DECL_BITFIELD(DSTSCControlByte, uint8_t); +// TODO +DECL_BITS(DSTSCControlByte, Channel, 4, 3); +DECL_BIT(DSTSCControlByte, Control, 7); + enum { DS_SPI_DEV_POWERMAN = 0, DS_SPI_DEV_FIRMWARE = 1, DS_SPI_DEV_TSC = 2 }; +enum { + DS_TSC_CHANNEL_TEMP_0 = 0, + DS_TSC_CHANNEL_TS_Y = 1, + DS_TSC_CHANNEL_BATTERY_V = 2, + DS_TSC_CHANNEL_TS_Z1 = 3, + DS_TSC_CHANNEL_TS_Z2 = 4, + DS_TSC_CHANNEL_TS_X = 5, + DS_TSC_CHANNEL_MIC = 6, + DS_TSC_CHANNEL_TEMP_1 = 7, +}; + +struct DSSPIBus { + bool holdEnabled; + + uint8_t firmwareMode; + + struct mTimingEvent tscEvent; + uint8_t tscControlByte; + uint16_t tscRegister; + int tscOffset; + + uint8_t powmgrByte; +}; + struct DS; +void DSSPIReset(struct DS* ds); DSSPICNT DSSPIWriteControl(struct DS* ds, uint16_t control); void DSSPIWrite(struct DS* ds, uint8_t datum);
M
src/ds/io.c
→
src/ds/io.c
@@ -246,7 +246,7 @@ value = DSSPIWriteControl(ds, value);
break; case DS7_REG_SPIDATA: DSSPIWrite(ds, value); - return; + break; default: { uint32_t v2 = DSIOWrite(&ds->ds7, address, value);
M
src/ds/memory.c
→
src/ds/memory.c
@@ -181,6 +181,8 @@ ds->memory.slot2Owner = true;
ds->ds7.memory.slot1Access = true; ds->ds9.memory.slot1Access = false; + DSSPIReset(ds); + DSVideoConfigureVRAM(ds, 0, 0); DSVideoConfigureVRAM(ds, 1, 0); DSVideoConfigureVRAM(ds, 2, 0);
M
src/ds/spi.c
→
src/ds/spi.c
@@ -9,13 +9,95 @@ #include <mgba/internal/ds/ds.h>
mLOG_DEFINE_CATEGORY(DS_SPI, "DS SPI"); +static void _tscEvent(struct mTiming*, 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; +} + DSSPICNT DSSPIWriteControl(struct DS* ds, uint16_t control) { // TODO - mLOG(DS_SPI, STUB, "Unimplemented control write: %04X", control); + if (!ds->memory.spiBus.holdEnabled) { + ds->memory.spiBus.tscControlByte = 0; + } + ds->memory.spiBus.holdEnabled = DSSPICNTIsCSHold(control); return control; } void DSSPIWrite(struct DS* ds, uint8_t datum) { - mLOG(DS_SPI, STUB, "Unimplemented data write: %02X", datum); - // TODO + DSSPICNT control = ds->memory.io7[DS7_REG_SPICNT >> 1]; + if (!DSSPICNTIsEnable(control)) { + return; + } + uint32_t baud = 19 - DSSPICNTGetBaud(control); + 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); + break; + case DS_SPI_DEV_POWERMAN: + case DS_SPI_DEV_FIRMWARE: + default: + mLOG(DS_SPI, STUB, "Unimplemented data write: %04X:%02X", control, datum); + break; + } + ds->memory.io7[DS7_REG_SPICNT >> 1] = control; +} + +static void _tscEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { + 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; + + // TODO: /PENIRQ + if (ds->memory.spiBus.tscOffset > 0) { + // TODO: Make generic? + if (ds->memory.spiBus.tscOffset < 12) { + newValue = (ds->memory.spiBus.tscRegister & 0x1F) << 3; + ds->memory.spiBus.tscOffset = 12; + } else { + newValue = 0; + } + } else if (ds->memory.spiBus.tscControlByte) { + switch (DSTSCControlByteGetChannel(ds->memory.spiBus.tscControlByte)) { + case DS_TSC_CHANNEL_TS_X: + mLOG(DS_SPI, STUB, "Unimplemented TSC channel X"); + ds->memory.spiBus.tscRegister = 0; + break; + case DS_TSC_CHANNEL_TS_Y: + mLOG(DS_SPI, STUB, "Unimplemented TSC channel Y"); + ds->memory.spiBus.tscRegister = 0xFFF; + break; + case DS_TSC_CHANNEL_TEMP_0: + case DS_TSC_CHANNEL_BATTERY_V: + case DS_TSC_CHANNEL_TS_Z1: + case DS_TSC_CHANNEL_TS_Z2: + case DS_TSC_CHANNEL_MIC: + case DS_TSC_CHANNEL_TEMP_1: + ds->memory.spiBus.tscRegister = 0; + mLOG(DS_SPI, STUB, "Unimplemented TSC channel %i", DSTSCControlByteGetChannel(ds->memory.spiBus.tscControlByte)); + } + newValue = (ds->memory.spiBus.tscRegister >> 5) & 0x7F; + ds->memory.spiBus.tscOffset = 7; + } + + if (DSTSCControlByteIsControl(oldValue)) { + ds->memory.spiBus.tscControlByte = oldValue; + ds->memory.spiBus.tscOffset = 0; + } + + 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); + } }