DS Slot-1: Implement Slot-1 DMAs
Vicki Pfau vi@endrift.com
Sun, 26 Feb 2017 14:07:08 -0800
3 files changed,
49 insertions(+),
3 deletions(-)
M
include/mgba/internal/ds/slot1.h
→
include/mgba/internal/ds/slot1.h
@@ -46,6 +46,8 @@ uint32_t transferRemaining;
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
M
src/ds/dma.c
→
src/ds/dma.c
@@ -81,15 +81,24 @@ }
} 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"); }
M
src/ds/slot1.c
→
src/ds/slot1.c
@@ -7,6 +7,7 @@ #include <mgba/internal/ds/slot1.h>
#include <mgba/internal/arm/macros.h> #include <mgba/internal/ds/ds.h> +#include <mgba/internal/ds/dma.h> #include <mgba-util/math.h> #include <mgba-util/vfs.h>@@ -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 @@ } else {
cycles = 5; } if (!ds->ds7.memory.slot1Access) { - cycles << 1; + cycles <<= 1; } cycles -= cyclesLate; mTimingDeschedule(timing, &ds->memory.slot1.transferEvent);@@ -64,6 +66,30 @@ // TODO: Error check
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 @@ slot1->spiData = slot1->spiVf->map(slot1->spiVf, slot1->spiVf->size(slot1->spiVf), MAP_WRITE);
} return slot1->spiData; } + +void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info) { + dscore->p->memory.slot1.dmaSource = number; +}