all repos — mgba @ d157fd6037d00d14e27c855b2d7bb29c2b3ea2d5

mGBA Game Boy Advance Emulator

DS Slot-1: Cart timing and IRQs
Vicki Pfau vi@endrift.com
Sun, 26 Feb 2017 12:06:52 -0800
commit

d157fd6037d00d14e27c855b2d7bb29c2b3ea2d5

parent

aac95687698b1912ba5ce8604db943c1d16d48e9

2 files changed, 43 insertions(+), 4 deletions(-)

jump to
M include/mgba/internal/ds/slot1.hinclude/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.csrc/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; }