DS Slot-1: Emulate KEY delay, improve timing
Vicki Pfau vi@endrift.com
Tue, 25 Apr 2017 00:37:06 -0700
3 files changed,
38 insertions(+),
22 deletions(-)
M
include/mgba/internal/ds/slot1.h
→
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);
M
src/ds/slot1.c
→
src/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; }