GBA Memory: Fix DMA timing

This commit is contained in:
Jeffrey Pfau 2016-12-13 18:04:12 -08:00
parent 82a0088e1e
commit a1689c80a7
4 changed files with 29 additions and 4 deletions

View File

@ -68,6 +68,10 @@ int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
return *timing->nextEvent;
}
int32_t mTimingCurrentTime(struct mTiming* timing) {
return timing->masterCycles + *timing->relativeCycles;
}
int32_t mTimingNextEvent(struct mTiming* timing) {
struct mTimingEvent* next = timing->root;
if (!next) {

View File

@ -32,6 +32,7 @@ void mTimingClear(struct mTiming* timing);
void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when);
void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*);
int32_t mTimingTick(struct mTiming* timing, int32_t cycles);
int32_t mTimingCurrentTime(struct mTiming* timing);
int32_t mTimingNextEvent(struct mTiming* timing);
#endif

View File

@ -1555,8 +1555,9 @@ void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) {
info->hasStarted = 0;
switch (GBADMARegisterGetTiming(info->reg)) {
case DMA_TIMING_NOW:
info->nextEvent = 2;
GBAMemoryUpdateDMAs(gba, -1);
info->nextEvent = 2 + 1; // XXX: Account for I cycle when writing
info->scheduledAt = mTimingCurrentTime(&gba->timing);
GBAMemoryUpdateDMAs(gba, 0);
break;
case DMA_TIMING_HBLANK:
// Handled implicitly
@ -1586,27 +1587,43 @@ void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) {
void GBAMemoryRunHblankDMAs(struct GBA* gba, int32_t cycles) {
struct GBAMemory* memory = &gba->memory;
struct GBADMA* dma;
bool dmaSeen = false;
if (memory->activeDMA >= 0) {
GBAMemoryUpdateDMAs(gba, mTimingCurrentTime(&gba->timing) - memory->dma[memory->activeDMA].scheduledAt);
}
int i;
for (i = 0; i < 4; ++i) {
dma = &memory->dma[i];
if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK) {
dma->nextEvent = 2 + cycles;
dma->scheduledAt = mTimingCurrentTime(&gba->timing);
dmaSeen = true;
}
}
GBAMemoryUpdateDMAs(gba, 0);
if (dmaSeen) {
GBAMemoryUpdateDMAs(gba, 0);
}
}
void GBAMemoryRunVblankDMAs(struct GBA* gba, int32_t cycles) {
struct GBAMemory* memory = &gba->memory;
struct GBADMA* dma;
bool dmaSeen = false;
if (memory->activeDMA >= 0) {
GBAMemoryUpdateDMAs(gba, mTimingCurrentTime(&gba->timing) - memory->dma[memory->activeDMA].scheduledAt);
}
int i;
for (i = 0; i < 4; ++i) {
dma = &memory->dma[i];
if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK) {
dma->nextEvent = 2 + cycles;
dma->scheduledAt = mTimingCurrentTime(&gba->timing);
dmaSeen = true;
}
}
GBAMemoryUpdateDMAs(gba, 0);
if (dmaSeen) {
GBAMemoryUpdateDMAs(gba, 0);
}
}
void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) {
@ -1664,6 +1681,7 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
if (info->hasStarted < 1) {
info->hasStarted = wordsRemaining;
info->nextEvent = 0;
info->scheduledAt = mTimingCurrentTime(&gba->timing);
GBAMemoryUpdateDMAs(gba, -cycles);
return;
}
@ -1729,6 +1747,7 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
} else {
info->nextDest = dest;
info->nextCount = wordsRemaining;
info->scheduledAt = mTimingCurrentTime(&gba->timing);
}
info->nextSource = source;
GBAMemoryUpdateDMAs(gba, 0);

View File

@ -109,6 +109,7 @@ struct GBADMA {
uint32_t nextDest;
int32_t nextCount;
int32_t nextEvent;
uint32_t scheduledAt;
int32_t hasStarted;
};