all repos — mgba @ d5d7349259c1076bc000d70ac30d1938ed161292

mGBA Game Boy Advance Emulator

DS GX: Handle buffer fullness better
Vicki Pfau vi@endrift.com
Wed, 01 Mar 2017 01:00:22 -0800
commit

d5d7349259c1076bc000d70ac30d1938ed161292

parent

2fa9d363b39b0b3dacdbc1d59205c4c6a70ce363

2 files changed, 38 insertions(+), 17 deletions(-)

jump to
M src/ds/dma.csrc/ds/dma.c

@@ -115,8 +115,14 @@ if (dma->nextCount == dma->count) {

dma->when = mTimingCurrentTime(&dscore->timing); } if (dma->nextCount & 0xFFFFF) { - dscore->p->cpuBlocked |= DS_CPU_BLOCK_DMA; // TODO: Fix for ITCM - DSDMAService(dscore, memory->activeDMA, dma); + if (dscore->p->cpuBlocked & ~DS_CPU_BLOCK_DMA) { + // Delay DMA until after the CPU unblocks + dma->when = mTimingCurrentTime(&dscore->timing) + mTimingNextEvent(&dscore->timing) + 1; + DSDMAUpdate(dscore); + } else { + dscore->p->cpuBlocked |= DS_CPU_BLOCK_DMA; // TODO: Fix for ITCM + DSDMAService(dscore, memory->activeDMA, dma); + } } else { dma->nextCount = 0; if (!GBADMARegisterIsRepeat(dma->reg) || GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_NOW) {
M src/ds/gx.csrc/ds/gx.c

@@ -223,6 +223,23 @@ ++gx->polygonIndex;

} } +static void _flushOutstanding(struct DSGX* gx) { + if (CircleBufferSize(&gx->fifo) == (DS_GX_FIFO_SIZE * sizeof(struct DSGXEntry))) { + return; + } + if (gx->p->cpuBlocked & DS_CPU_BLOCK_GX) { + gx->p->cpuBlocked &= ~DS_CPU_BLOCK_GX; + DSGXWriteFIFO(gx, gx->outstandingEntry); + gx->outstandingEntry.command = 0; + } + while (gx->outstandingCommand[0] && !gx->outstandingParams[0]) { + if (CircleBufferSize(&gx->fifo) == (DS_GX_FIFO_SIZE * sizeof(struct DSGXEntry))) { + return; + } + DSGXWriteFIFO(gx, (struct DSGXEntry) { 0 }); + } +} + static void _fifoRun(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct DSGX* gx = context; uint32_t cycles;

@@ -647,6 +664,7 @@ }

if (cycles && !gx->swapBuffers) { mTimingSchedule(timing, &gx->fifoEvent, cycles - cyclesLate); } + _flushOutstanding(gx); DSGXUpdateGXSTAT(gx); }

@@ -739,11 +757,6 @@

value = DSRegGXSTATSetBusy(value, mTimingIsScheduled(&gx->p->ds9.timing, &gx->fifoEvent) || gx->swapBuffers); gx->p->memory.io9[DS9_REG_GXSTAT_HI >> 1] = value >> 16; - - if (gx->p->cpuBlocked & DS_CPU_BLOCK_GX && entries < DS_GX_FIFO_SIZE) { - DSGXWriteFIFO(gx, gx->outstandingEntry); - gx->p->cpuBlocked &= ~DS_CPU_BLOCK_GX; - } } static void DSGXUnpackCommand(struct DSGX* gx, uint32_t command) {

@@ -767,12 +780,21 @@ gx->outstandingParams[0] = _gxCommandParams[gx->outstandingCommand[0]];

gx->outstandingParams[1] = _gxCommandParams[gx->outstandingCommand[1]]; gx->outstandingParams[2] = _gxCommandParams[gx->outstandingCommand[2]]; gx->outstandingParams[3] = _gxCommandParams[gx->outstandingCommand[3]]; - while (gx->outstandingCommand[0] && !gx->outstandingParams[0]) { - DSGXWriteFIFO(gx, (struct DSGXEntry) { gx->outstandingCommand[0] }); } + _flushOutstanding(gx); } static void DSGXWriteFIFO(struct DSGX* gx, struct DSGXEntry entry) { + if (CircleBufferSize(&gx->fifo) == (DS_GX_FIFO_SIZE * sizeof(entry))) { + mLOG(DS_GX, INFO, "FIFO full"); + if (gx->p->cpuBlocked & DS_CPU_BLOCK_GX) { + abort(); + } + gx->p->cpuBlocked |= DS_CPU_BLOCK_GX; + gx->outstandingEntry = entry; + gx->p->ds9.cpu->nextEvent = 0; + return; + } if (gx->outstandingCommand[0]) { entry.command = gx->outstandingCommand[0]; if (gx->outstandingParams[0]) {

@@ -810,19 +832,12 @@ CircleBufferWrite8(&gx->fifo, entry.params[0]);

CircleBufferWrite8(&gx->fifo, entry.params[1]); CircleBufferWrite8(&gx->fifo, entry.params[2]); CircleBufferWrite8(&gx->fifo, entry.params[3]); - } else { - mLOG(DS_GX, STUB, "Unimplemented GX full"); - gx->p->cpuBlocked |= DS_CPU_BLOCK_GX; - gx->outstandingEntry = entry; - gx->p->ds9.cpu->nextEvent = 0; } if (!gx->swapBuffers && !mTimingIsScheduled(&gx->p->ds9.timing, &gx->fifoEvent)) { mTimingSchedule(&gx->p->ds9.timing, &gx->fifoEvent, cycles); } - if (gx->outstandingCommand[0] && !gx->outstandingParams[0]) { - DSGXWriteFIFO(gx, (struct DSGXEntry) { gx->outstandingCommand[0] }); - } + _flushOutstanding(gx); } uint16_t DSGXWriteRegister(struct DSGX* gx, uint32_t address, uint16_t value) {