diff --git a/include/mgba/internal/ds/slot1.h b/include/mgba/internal/ds/slot1.h index bbe764b79..4652ee9a4 100644 --- a/include/mgba/internal/ds/slot1.h +++ b/include/mgba/internal/ds/slot1.h @@ -46,6 +46,8 @@ struct DSSlot1 { struct mTimingEvent transferEvent; uint8_t readBuffer[4]; + int dmaSource; + enum DSSavedataType savedataType; struct mTimingEvent spiEvent; bool spiHoldEnabled; @@ -64,9 +66,14 @@ 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); void DSSlot1WriteSPI(struct DSCommon* dscore, uint8_t datum); + +struct GBADMA; +void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info); + uint32_t DSSlot1Read(struct DS* ds); CXX_GUARD_END diff --git a/src/ds/dma.c b/src/ds/dma.c index 54c5ab21d..d8c46f855 100644 --- a/src/ds/dma.c +++ b/src/ds/dma.c @@ -81,15 +81,24 @@ void DS9DMAWriteCNT(struct DSCommon* dscore, int dma, uint32_t value) { } void DSDMASchedule(struct DSCommon* dscore, int number, struct GBADMA* info) { - switch (GBADMARegisterGetTiming(info->reg)) { + int which; + if (dscore == &dscore->p->ds9) { + which = GBADMARegisterGetTiming9(info->reg); + } else { + which = GBADMARegisterGetTiming(info->reg); + } + switch (which) { case DS_DMA_TIMING_NOW: info->when = mTimingCurrentTime(&dscore->timing) + 3; // DMAs take 3 cycles to start info->nextCount = info->count; break; - case DS_DMA_TIMING_HBLANK: case DS_DMA_TIMING_VBLANK: // Handled implicitly return; + case DS9_DMA_TIMING_SLOT1: + DSSlot1ScheduleDMA(dscore, number, info); + return; + case DS_DMA_TIMING_HBLANK: // DS7_DMA_TIMING_SLOT1 default: mLOG(DS_MEM, STUB, "Unimplemented DMA"); } diff --git a/src/ds/slot1.c b/src/ds/slot1.c index e1dcb677b..5ffbb77c8 100644 --- a/src/ds/slot1.c +++ b/src/ds/slot1.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -35,6 +36,7 @@ void DSSlot1Reset(struct DS* ds) { ds->memory.slot1.statusReg = 0; ds->memory.slot1.spiCommand = 0; ds->memory.slot1.spiHoldEnabled = 0; + ds->memory.slot1.dmaSource = -1; } static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t cyclesLate) { @@ -46,7 +48,7 @@ static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t cy cycles = 5; } if (!ds->ds7.memory.slot1Access) { - cycles << 1; + cycles <<= 1; } cycles -= cyclesLate; mTimingDeschedule(timing, &ds->memory.slot1.transferEvent); @@ -64,6 +66,30 @@ static void _transferEvent(struct mTiming* timing, void* context, uint32_t cycle ds->memory.slot1.address += 4; ds->memory.slot1.transferRemaining -= 4; romcnt = DSSlot1ROMCNTFillWordReady(romcnt); + + if (ds->memory.slot1.dmaSource >= 0) { + struct DSCommon* dscore; + if (ds->ds7.memory.slot1Access) { + dscore = &ds->ds7; + } else { + dscore = &ds->ds9; + } + struct GBADMA* dma = &dscore->memory.dma[ds->memory.slot1.dmaSource]; + bool cond = false; + if (ds->ds7.memory.slot1Access && GBADMARegisterGetTiming(dma->reg) == DS7_DMA_TIMING_SLOT1) { + cond = true; + } + if (ds->ds9.memory.slot1Access && GBADMARegisterGetTiming9(dma->reg) == DS9_DMA_TIMING_SLOT1) { + cond = true; + } + if (cond) { + dma->when = mTimingCurrentTime(timing); + dma->nextCount = 1; + DSDMAUpdate(dscore); + } else { + ds->memory.slot1.dmaSource = -1; + } + } } else { DSSlot1AUXSPICNT config = ds->memory.io7[DS_REG_AUXSPICNT >> 1]; memset(ds->memory.slot1.readBuffer, 0, 4); @@ -331,3 +357,7 @@ static bool _slot1GuaranteeSize(struct DSSlot1* slot1) { } return slot1->spiData; } + +void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info) { + dscore->p->memory.slot1.dmaSource = number; +}