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; struct mTimingEvent transferEvent;
uint8_t readBuffer[4]; uint8_t readBuffer[4];
int dmaSource;
enum DSSavedataType savedataType; enum DSSavedataType savedataType;
struct mTimingEvent spiEvent; struct mTimingEvent spiEvent;
bool spiHoldEnabled; bool spiHoldEnabled;
@ -64,9 +66,14 @@ struct DS;
struct DSCommon; struct DSCommon;
void DSSlot1SPIInit(struct DS* ds, struct VFile* vf); void DSSlot1SPIInit(struct DS* ds, struct VFile* vf);
void DSSlot1Reset(struct DS* ds); void DSSlot1Reset(struct DS* ds);
DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config); DSSlot1AUXSPICNT DSSlot1Configure(struct DS* ds, DSSlot1AUXSPICNT config);
DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control); DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control);
void DSSlot1WriteSPI(struct DSCommon* dscore, uint8_t datum); 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); uint32_t DSSlot1Read(struct DS* ds);
CXX_GUARD_END 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) { 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: case DS_DMA_TIMING_NOW:
info->when = mTimingCurrentTime(&dscore->timing) + 3; // DMAs take 3 cycles to start info->when = mTimingCurrentTime(&dscore->timing) + 3; // DMAs take 3 cycles to start
info->nextCount = info->count; info->nextCount = info->count;
break; break;
case DS_DMA_TIMING_HBLANK:
case DS_DMA_TIMING_VBLANK: case DS_DMA_TIMING_VBLANK:
// Handled implicitly // Handled implicitly
return; return;
case DS9_DMA_TIMING_SLOT1:
DSSlot1ScheduleDMA(dscore, number, info);
return;
case DS_DMA_TIMING_HBLANK: // DS7_DMA_TIMING_SLOT1
default: default:
mLOG(DS_MEM, STUB, "Unimplemented DMA"); mLOG(DS_MEM, STUB, "Unimplemented DMA");
} }

View File

@ -7,6 +7,7 @@
#include <mgba/internal/arm/macros.h> #include <mgba/internal/arm/macros.h>
#include <mgba/internal/ds/ds.h> #include <mgba/internal/ds/ds.h>
#include <mgba/internal/ds/dma.h>
#include <mgba-util/math.h> #include <mgba-util/math.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
@ -35,6 +36,7 @@ void DSSlot1Reset(struct DS* ds) {
ds->memory.slot1.statusReg = 0; ds->memory.slot1.statusReg = 0;
ds->memory.slot1.spiCommand = 0; ds->memory.slot1.spiCommand = 0;
ds->memory.slot1.spiHoldEnabled = 0; ds->memory.slot1.spiHoldEnabled = 0;
ds->memory.slot1.dmaSource = -1;
} }
static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t cyclesLate) { 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; cycles = 5;
} }
if (!ds->ds7.memory.slot1Access) { if (!ds->ds7.memory.slot1Access) {
cycles << 1; cycles <<= 1;
} }
cycles -= cyclesLate; cycles -= cyclesLate;
mTimingDeschedule(timing, &ds->memory.slot1.transferEvent); 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.address += 4;
ds->memory.slot1.transferRemaining -= 4; ds->memory.slot1.transferRemaining -= 4;
romcnt = DSSlot1ROMCNTFillWordReady(romcnt); 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 { } else {
DSSlot1AUXSPICNT config = ds->memory.io7[DS_REG_AUXSPICNT >> 1]; DSSlot1AUXSPICNT config = ds->memory.io7[DS_REG_AUXSPICNT >> 1];
memset(ds->memory.slot1.readBuffer, 0, 4); memset(ds->memory.slot1.readBuffer, 0, 4);
@ -331,3 +357,7 @@ static bool _slot1GuaranteeSize(struct DSSlot1* slot1) {
} }
return slot1->spiData; return slot1->spiData;
} }
void DSSlot1ScheduleDMA(struct DSCommon* dscore, int number, struct GBADMA* info) {
dscore->p->memory.slot1.dmaSource = number;
}