From 04541e3b1d7f9f067d2a8faf589c7093e201ff82 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Apr 2017 00:37:06 -0700 Subject: [PATCH] DS Slot-1: Emulate KEY delay, improve timing --- CHANGES | 1 + include/mgba/internal/ds/slot1.h | 2 ++ src/ds/slot1.c | 57 ++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index 078ac0e9c..60a53f291 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ Misc: - DS: Attempt to detect if a game is homebrew - Qt: Add .srl as an extension for DS ROMs - FFmpeg: Allow framerate to be adjusted + - DS Slot-1: Emulate KEY delay 0.6.0: (Future) Features: diff --git a/include/mgba/internal/ds/slot1.h b/include/mgba/internal/ds/slot1.h index b223e45ba..cb4a2e88c 100644 --- a/include/mgba/internal/ds/slot1.h +++ b/include/mgba/internal/ds/slot1.h @@ -24,6 +24,8 @@ DECL_BIT(DSSlot1AUXSPICNT, DoIRQ, 14); DECL_BIT(DSSlot1AUXSPICNT, Enable, 15); DECL_BITFIELD(DSSlot1ROMCNT, uint32_t); +DECL_BITS(DSSlot1ROMCNT, Delay, 0, 12); +DECL_BITS(DSSlot1ROMCNT, Gap, 16, 5); DECL_BIT(DSSlot1ROMCNT, WordReady, 23); DECL_BITS(DSSlot1ROMCNT, BlockSize, 24, 3); DECL_BIT(DSSlot1ROMCNT, TransferRate, 27); diff --git a/src/ds/slot1.c b/src/ds/slot1.c index df98ff968..0157db962 100644 --- a/src/ds/slot1.c +++ b/src/ds/slot1.c @@ -49,10 +49,11 @@ static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t by } else { cycles = 5; } + cycles *= bytes; + if (!ds->ds7.memory.slot1Access) { cycles <<= 1; } - cycles *= bytes / 4; cycles -= cyclesLate; mTimingDeschedule(timing, &ds->memory.slot1.transferEvent); mTimingSchedule(timing, &ds->memory.slot1.transferEvent, cycles); @@ -91,23 +92,20 @@ static void _transferEvent(struct mTiming* timing, void* context, uint32_t cycle ds->memory.slot1.dmaSource = -1; } - if (ds->memory.slot1.transferRemaining) { - ds->romVf->read(ds->romVf, ds->memory.slot1.readBuffer, 4); - // TODO: Error check - ds->memory.slot1.address += 4; - ds->memory.slot1.transferRemaining -= 4; - romcnt = DSSlot1ROMCNTFillWordReady(romcnt); + ds->romVf->read(ds->romVf, ds->memory.slot1.readBuffer, 4); + // TODO: Error check + ds->memory.slot1.address += 4; + ds->memory.slot1.transferRemaining -= 4; + romcnt = DSSlot1ROMCNTFillWordReady(romcnt); - if (hasDMA) { - dma->when = mTimingCurrentTime(timing); - dma->nextCount = 1; - DSDMAUpdate(dscore); - } - } else { + if (hasDMA) { + dma->when = mTimingCurrentTime(timing); + dma->nextCount = 1; + DSDMAUpdate(dscore); + } + + if (!ds->memory.slot1.transferRemaining) { DSSlot1AUXSPICNT config = ds->memory.io7[DS_REG_AUXSPICNT >> 1]; - memset(ds->memory.slot1.readBuffer, 0, 4); - romcnt = DSSlot1ROMCNTClearWordReady(romcnt); - romcnt = DSSlot1ROMCNTClearBlockBusy(romcnt); if (DSSlot1AUXSPICNTIsDoIRQ(config)) { DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_SLOT1_TRANS); } @@ -142,10 +140,13 @@ static void DSSlot1StartTransfer(struct DS* ds) { ds->romVf->seek(ds->romVf, ds->memory.slot1.address, SEEK_SET); } ds->memory.slot1.transferRemaining = ds->memory.slot1.transferSize; + + DSSlot1ROMCNT romcnt = ds->memory.io7[DS_REG_ROMCNT_LO >> 1]; + unsigned delay = DSSlot1ROMCNTGetDelay(romcnt) + 12; if (ds->ds7.memory.slot1Access) { - _scheduleTransfer(ds, &ds->ds7.timing, 12, 0); + _scheduleTransfer(ds, &ds->ds7.timing, delay, 0); } else { - _scheduleTransfer(ds, &ds->ds9.timing, 12, 0); + _scheduleTransfer(ds, &ds->ds9.timing, delay, 0); } break; case 0xB8: @@ -185,7 +186,6 @@ DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control) { } if (DSSlot1ROMCNTIsBlockBusy(control)) { DSSlot1StartTransfer(ds); - // TODO: timing if (ds->memory.slot1.command[0] != 0xB7) { control = DSSlot1ROMCNTFillWordReady(control); } @@ -196,11 +196,24 @@ DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control) { uint32_t DSSlot1Read(struct DS* ds) { uint32_t result; LOAD_32(result, 0, ds->memory.slot1.readBuffer); - if (ds->ds7.memory.slot1Access) { - _scheduleTransfer(ds, &ds->ds7.timing, 4, 0); + + DSSlot1ROMCNT romcnt; + // TODO: Big endian + LOAD_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7); + romcnt = DSSlot1ROMCNTClearWordReady(romcnt); + + if (ds->memory.slot1.transferRemaining) { + if (ds->ds7.memory.slot1Access) { + _scheduleTransfer(ds, &ds->ds7.timing, 4, 0); + } else { + _scheduleTransfer(ds, &ds->ds9.timing, 4, 0); + } } else { - _scheduleTransfer(ds, &ds->ds9.timing, 4, 0); + romcnt = DSSlot1ROMCNTClearBlockBusy(romcnt); } + STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7); + STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io9); + return result; }