From d157fd6037d00d14e27c855b2d7bb29c2b3ea2d5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 26 Feb 2017 12:06:52 -0800 Subject: [PATCH] DS Slot-1: Cart timing and IRQs --- include/mgba/internal/ds/slot1.h | 2 ++ src/ds/slot1.c | 45 +++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/include/mgba/internal/ds/slot1.h b/include/mgba/internal/ds/slot1.h index 1dc9699fb..bbe764b79 100644 --- a/include/mgba/internal/ds/slot1.h +++ b/include/mgba/internal/ds/slot1.h @@ -26,6 +26,7 @@ DECL_BIT(DSSlot1AUXSPICNT, Enable, 15); DECL_BITFIELD(DSSlot1ROMCNT, uint32_t); DECL_BIT(DSSlot1ROMCNT, WordReady, 23); DECL_BITS(DSSlot1ROMCNT, BlockSize, 24, 3); +DECL_BIT(DSSlot1ROMCNT, TransferRate, 27); DECL_BIT(DSSlot1ROMCNT, BlockBusy, 31); enum DSSavedataType { @@ -42,6 +43,7 @@ struct DSSlot1 { uint32_t address; uint32_t transferSize; uint32_t transferRemaining; + struct mTimingEvent transferEvent; uint8_t readBuffer[4]; enum DSSavedataType savedataType; diff --git a/src/ds/slot1.c b/src/ds/slot1.c index 7cad5afd2..e1dcb677b 100644 --- a/src/ds/slot1.c +++ b/src/ds/slot1.c @@ -13,6 +13,7 @@ mLOG_DEFINE_CATEGORY(DS_SLOT1, "DS Slot-1"); static void _slot1SPI(struct mTiming*, void* context, uint32_t cyclesLate); +static void _transferEvent(struct mTiming* timing, void* context, uint32_t cyclesLate); static bool _slot1GuaranteeSize(struct DSSlot1*); void DSSlot1SPIInit(struct DS* ds, struct VFile* vf) { @@ -20,6 +21,10 @@ void DSSlot1SPIInit(struct DS* ds, struct VFile* vf) { ds->memory.slot1.spiEvent.priority = 0x70; ds->memory.slot1.spiEvent.context = NULL; ds->memory.slot1.spiEvent.callback = _slot1SPI; + ds->memory.slot1.transferEvent.name = "DS Slot-1 Transfer"; + ds->memory.slot1.transferEvent.priority = 0x71; + ds->memory.slot1.transferEvent.context = ds; + ds->memory.slot1.transferEvent.callback = _transferEvent; ds->memory.slot1.savedataType = DS_SAVEDATA_AUTODETECT; ds->memory.slot1.spiVf = vf; ds->memory.slot1.spiRealVf = vf; @@ -32,7 +37,24 @@ void DSSlot1Reset(struct DS* ds) { ds->memory.slot1.spiHoldEnabled = 0; } -static void DSSlot1StepTransfer(struct DS* ds) { +static void _scheduleTransfer(struct DS* ds, struct mTiming* timing, uint32_t cyclesLate) { + DSSlot1ROMCNT romcnt = ds->memory.io7[DS_REG_ROMCNT_HI >> 1] << 16; + uint32_t cycles; + if (DSSlot1ROMCNTIsTransferRate(romcnt)) { + cycles = 8; + } else { + cycles = 5; + } + if (!ds->ds7.memory.slot1Access) { + cycles << 1; + } + cycles -= cyclesLate; + mTimingDeschedule(timing, &ds->memory.slot1.transferEvent); + mTimingSchedule(timing, &ds->memory.slot1.transferEvent, cycles); +} + +static void _transferEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { + struct DS* ds = context; DSSlot1ROMCNT romcnt; // TODO: Big endian LOAD_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7); @@ -43,10 +65,17 @@ static void DSSlot1StepTransfer(struct DS* ds) { ds->memory.slot1.transferRemaining -= 4; romcnt = DSSlot1ROMCNTFillWordReady(romcnt); } else { + DSSlot1AUXSPICNT config = ds->memory.io7[DS_REG_AUXSPICNT >> 1]; memset(ds->memory.slot1.readBuffer, 0, 4); romcnt = DSSlot1ROMCNTClearWordReady(romcnt); - // TODO: IRQ romcnt = DSSlot1ROMCNTClearBlockBusy(romcnt); + if (DSSlot1AUXSPICNTIsDoIRQ(config)) { + if (ds->ds7.memory.slot1Access) { + DSRaiseIRQ(ds->ds7.cpu, ds->ds7.memory.io, DS_IRQ_SLOT1_TRANS); + } else { + DSRaiseIRQ(ds->ds9.cpu, ds->ds9.memory.io, DS_IRQ_SLOT1_TRANS); + } + } } STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io7); STORE_32(romcnt, DS_REG_ROMCNT_LO, ds->memory.io9); @@ -70,7 +99,11 @@ 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; - DSSlot1StepTransfer(ds); + if (ds->ds7.memory.slot1Access) { + _scheduleTransfer(ds, &ds->ds7.timing, 0); + } else { + _scheduleTransfer(ds, &ds->ds9.timing, 0); + } break; case 0xB8: memcpy(ds->memory.slot1.readBuffer, DS_CHIP_ID, 4); @@ -118,7 +151,11 @@ DSSlot1ROMCNT DSSlot1Control(struct DS* ds, DSSlot1ROMCNT control) { uint32_t DSSlot1Read(struct DS* ds) { uint32_t result; LOAD_32(result, 0, ds->memory.slot1.readBuffer); - DSSlot1StepTransfer(ds); + if (ds->ds7.memory.slot1Access) { + _scheduleTransfer(ds, &ds->ds7.timing, 0); + } else { + _scheduleTransfer(ds, &ds->ds9.timing, 0); + } return result; }