DS Slot-1: Implement Slot-1 DMAs

This commit is contained in:
Vicki Pfau 2017-02-26 14:07:08 -08:00
parent 9c40ebb301
commit cf5d6709fe
3 changed files with 49 additions and 3 deletions

View File

@ -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

View File

@ -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");
}

View File

@ -7,6 +7,7 @@
#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 @@ 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;
}