all repos — mgba @ 04541e3b1d7f9f067d2a8faf589c7093e201ff82

mGBA Game Boy Advance Emulator

DS Slot-1: Emulate KEY delay, improve timing
Vicki Pfau vi@endrift.com
Tue, 25 Apr 2017 00:37:06 -0700
commit

04541e3b1d7f9f067d2a8faf589c7093e201ff82

parent

7879736a44c167373c04c9381218a131ee1bd5c5

3 files changed, 38 insertions(+), 22 deletions(-)

jump to
M CHANGESCHANGES

@@ -34,6 +34,7 @@ - ARM9: Implement STRD/LDRD

- 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:
M include/mgba/internal/ds/slot1.hinclude/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);
M src/ds/slot1.csrc/ds/slot1.c

@@ -49,10 +49,11 @@ cycles = 8;

} 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 @@ if (!hasDMA) {

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 @@ if (ds->romVf) {

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 @@ return control;

} if (DSSlot1ROMCNTIsBlockBusy(control)) { DSSlot1StartTransfer(ds); - // TODO: timing if (ds->memory.slot1.command[0] != 0xB7) { control = DSSlot1ROMCNTFillWordReady(control); }

@@ -196,11 +196,24 @@

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; }