DS Slot-1: Cart timing and IRQs
Vicki Pfau vi@endrift.com
Sun, 26 Feb 2017 12:06:52 -0800
2 files changed,
43 insertions(+),
4 deletions(-)
M
include/mgba/internal/ds/slot1.h
→
include/mgba/internal/ds/slot1.h
@@ -26,6 +26,7 @@
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 @@ uint8_t command[8];
uint32_t address; uint32_t transferSize; uint32_t transferRemaining; + struct mTimingEvent transferEvent; uint8_t readBuffer[4]; enum DSSavedataType savedataType;
M
src/ds/slot1.c
→
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 @@ ds->memory.slot1.spiEvent.name = "DS Slot-1 SPI";
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 @@ ds->memory.slot1.spiCommand = 0;
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 @@ ds->memory.slot1.address += 4;
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 @@ if (ds->romVf) {
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 @@
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; }