Merge branch 'feature/ppc-savestates'
@@ -848,75 +848,84 @@ }
} void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) { - state->audio.ch1Volume = audio->ch1.envelope.currentVolume; - state->audio.ch1Dead = audio->ch1.envelope.dead; - state->audio.ch1Hi = audio->ch1.control.hi; - state->audio.ch1.envelopeNextStep = audio->ch1.envelope.nextStep; - state->audio.ch1.waveNextStep = audio->ch1.control.nextStep; - state->audio.ch1.sweepNextStep = audio->ch1.nextSweep; - state->audio.ch1.endTime = audio->ch1.control.endTime; - state->audio.ch1.nextEvent = audio->nextCh1; + uint32_t flags = 0; - state->audio.ch2Volume = audio->ch2.envelope.currentVolume; - state->audio.ch2Dead = audio->ch2.envelope.dead; - state->audio.ch2Hi = audio->ch2.control.hi; - state->audio.ch2.envelopeNextStep = audio->ch2.envelope.nextStep; - state->audio.ch2.waveNextStep = audio->ch2.control.nextStep; - state->audio.ch2.endTime = audio->ch2.control.endTime; - state->audio.ch2.nextEvent = audio->nextCh2; + flags = GBASerializedAudioFlagsSetCh1Volume(flags, audio->ch1.envelope.currentVolume); + flags = GBASerializedAudioFlagsSetCh1Dead(flags, audio->ch1.envelope.dead); + flags = GBASerializedAudioFlagsSetCh1Hi(flags, audio->ch1.control.hi); + STORE_32(audio->ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep); + STORE_32(audio->ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep); + STORE_32(audio->ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep); + STORE_32(audio->ch1.control.endTime, 0, &state->audio.ch1.endTime); + STORE_32(audio->nextCh1, 0, &state->audio.ch1.nextEvent); + + flags = GBASerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume); + flags = GBASerializedAudioFlagsSetCh2Dead(flags, audio->ch2.envelope.dead); + flags = GBASerializedAudioFlagsSetCh2Hi(flags, audio->ch2.control.hi); + STORE_32(audio->ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep); + STORE_32(audio->ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep); + STORE_32(audio->ch2.control.endTime, 0, &state->audio.ch2.endTime); + STORE_32(audio->nextCh2, 0, &state->audio.ch2.nextEvent); memcpy(state->audio.ch3.wavebanks, audio->ch3.wavedata, sizeof(state->audio.ch3.wavebanks)); - state->audio.ch3.endTime = audio->ch3.control.endTime; - state->audio.ch3.nextEvent = audio->nextCh3; + STORE_32(audio->ch3.control.endTime, 0, &state->audio.ch3.endTime); + STORE_32(audio->nextCh3, 0, &state->audio.ch3.nextEvent); + + state->audio.flags = GBASerializedAudioFlagsSetCh4Volume(flags, audio->ch4.envelope.currentVolume); + state->audio.flags = GBASerializedAudioFlagsSetCh4Dead(flags, audio->ch4.envelope.dead); + STORE_32(audio->ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep); + STORE_32(audio->ch4.lfsr, 0, &state->audio.ch4.lfsr); + STORE_32(audio->ch4.control.endTime, 0, &state->audio.ch4.endTime); + STORE_32(audio->nextCh4, 0, &state->audio.ch4.nextEvent); - state->audio.ch4Volume = audio->ch4.envelope.currentVolume; - state->audio.ch4Dead = audio->ch4.envelope.dead; - state->audio.ch4.envelopeNextStep = audio->ch4.envelope.nextStep; - state->audio.ch4.lfsr = audio->ch4.lfsr; - state->audio.ch4.endTime = audio->ch4.control.endTime; - state->audio.ch4.nextEvent = audio->nextCh4; + STORE_32(flags, 0, &state->audio.flags); CircleBufferDump(&audio->chA.fifo, state->audio.fifoA, sizeof(state->audio.fifoA)); CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB)); - state->audio.fifoSize = CircleBufferSize(&audio->chA.fifo); + uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo); + STORE_32(fifoSize, 0, &state->audio.fifoSize); - state->audio.nextEvent = audio->nextEvent; - state->audio.eventDiff = audio->eventDiff; - state->audio.nextSample = audio->nextSample; + STORE_32(audio->nextEvent, 0, &state->audio.nextEvent); + STORE_32(audio->eventDiff, 0, &state->audio.eventDiff); + STORE_32(audio->nextSample, 0, &state->audio.nextSample); } void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) { - audio->ch1.envelope.currentVolume = state->audio.ch1Volume; - audio->ch1.envelope.dead = state->audio.ch1Dead; - audio->ch1.control.hi = state->audio.ch1Hi; - audio->ch1.envelope.nextStep = state->audio.ch1.envelopeNextStep; - audio->ch1.control.nextStep = state->audio.ch1.waveNextStep; - audio->ch1.nextSweep = state->audio.ch1.sweepNextStep; - audio->ch1.control.endTime = state->audio.ch1.endTime; - audio->nextCh1 = state->audio.ch1.nextEvent; + uint32_t flags; + LOAD_32(flags, 0, &state->audio.flags); + audio->ch1.envelope.currentVolume = GBASerializedAudioFlagsGetCh1Volume(flags); + audio->ch1.envelope.dead = GBASerializedAudioFlagsGetCh1Dead(flags); + audio->ch1.control.hi = GBASerializedAudioFlagsGetCh1Hi(flags); + LOAD_32(audio->ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep); + LOAD_32(audio->ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep); + LOAD_32(audio->ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep); + LOAD_32(audio->ch1.control.endTime, 0, &state->audio.ch1.endTime); + LOAD_32(audio->nextCh1, 0, &state->audio.ch1.nextEvent); - audio->ch2.envelope.currentVolume = state->audio.ch2Volume; - audio->ch2.envelope.dead = state->audio.ch2Dead; - audio->ch2.control.hi = state->audio.ch2Hi; - audio->ch2.envelope.nextStep = state->audio.ch2.envelopeNextStep; - audio->ch2.control.nextStep = state->audio.ch2.waveNextStep; - audio->ch2.control.endTime = state->audio.ch2.endTime; - audio->nextCh2 = state->audio.ch2.nextEvent; + audio->ch2.envelope.currentVolume = GBASerializedAudioFlagsGetCh2Volume(flags); + audio->ch2.envelope.dead = GBASerializedAudioFlagsGetCh2Dead(flags); + audio->ch2.control.hi = GBASerializedAudioFlagsGetCh2Hi(flags); + LOAD_32(audio->ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep); + LOAD_32(audio->ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep); + LOAD_32(audio->ch2.control.endTime, 0, &state->audio.ch2.endTime); + LOAD_32(audio->nextCh2, 0, &state->audio.ch2.nextEvent); + // TODO: Big endian? memcpy(audio->ch3.wavedata, state->audio.ch3.wavebanks, sizeof(audio->ch3.wavedata)); - audio->ch3.control.endTime = state->audio.ch3.endTime; - audio->nextCh3 = state->audio.ch3.nextEvent; + LOAD_32(audio->ch3.control.endTime, 0, &state->audio.ch3.endTime); + LOAD_32(audio->nextCh3, 0, &state->audio.ch3.nextEvent); - audio->ch4.envelope.currentVolume = state->audio.ch4Volume; - audio->ch4.envelope.dead = state->audio.ch4Dead; - audio->ch4.envelope.nextStep = state->audio.ch4.envelopeNextStep; - audio->ch4.lfsr = state->audio.ch4.lfsr; - audio->ch4.control.endTime = state->audio.ch4.endTime; - audio->nextCh4 = state->audio.ch4.nextEvent; + audio->ch4.envelope.currentVolume = GBASerializedAudioFlagsGetCh4Volume(flags); + audio->ch4.envelope.dead = GBASerializedAudioFlagsGetCh4Dead(flags); + LOAD_32(audio->ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep); + LOAD_32(audio->ch4.lfsr, 0, &state->audio.ch4.lfsr); + LOAD_32(audio->ch4.control.endTime, 0, &state->audio.ch4.endTime); + LOAD_32(audio->nextCh4, 0, &state->audio.ch4.nextEvent); CircleBufferClear(&audio->chA.fifo); CircleBufferClear(&audio->chB.fifo); - size_t fifoSize = state->audio.fifoSize; + uint32_t fifoSize; + LOAD_32(fifoSize, 0, &state->audio.fifoSize); if (state->audio.fifoSize > CircleBufferCapacity(&audio->chA.fifo)) { fifoSize = CircleBufferCapacity(&audio->chA.fifo); }@@ -926,9 +935,9 @@ CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]);
CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]); } - audio->nextEvent = state->audio.nextEvent; - audio->eventDiff = state->audio.eventDiff; - audio->nextSample = state->audio.nextSample; + LOAD_32(audio->nextEvent, 0, &state->audio.nextEvent); + LOAD_32(audio->eventDiff, 0, &state->audio.eventDiff); + LOAD_32(audio->nextSample, 0, &state->audio.nextSample); } float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) {
@@ -128,7 +128,7 @@ bool stop;
int32_t endTime; } control; - unsigned lfsr; + uint32_t lfsr; int8_t sample; };
@@ -252,7 +252,7 @@ struct GBATimer* timer;
struct GBATimer* nextTimer; timer = &gba->timers[0]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; while (timer->nextEvent <= 0) {@@ -261,7 +261,7 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER0); }@@ -276,7 +276,7 @@ }
} nextTimer = &gba->timers[1]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM1CNT_LO >> 1]; if (!gba->memory.io[REG_TM1CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -287,7 +287,7 @@ nextEvent = timer->nextEvent;
} timer = &gba->timers[1]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -296,7 +296,7 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER1); }@@ -310,12 +310,12 @@ GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
} } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } nextTimer = &gba->timers[2]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM2CNT_LO >> 1]; if (!gba->memory.io[REG_TM2CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -328,7 +328,7 @@ }
} timer = &gba->timers[2]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -337,16 +337,16 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER2); } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } nextTimer = &gba->timers[3]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM3CNT_LO >> 1]; if (!gba->memory.io[REG_TM3CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -359,7 +359,7 @@ }
} timer = &gba->timers[3]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -368,11 +368,11 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER3); } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } }@@ -481,47 +481,47 @@ }
void GBATimerUpdateRegister(struct GBA* gba, int timer) { struct GBATimer* currentTimer = &gba->timers[timer]; - if (currentTimer->enable && !currentTimer->countUp) { + if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) { int32_t prefetchSkew = 0; if (gba->memory.lastPrefetchedPc - gba->memory.lastPrefetchedLoads * WORD_SIZE_THUMB >= (uint32_t) gba->cpu->gprs[ARM_PC]) { prefetchSkew = (gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * (gba->cpu->memory.activeSeqCycles16 + 1) / WORD_SIZE_THUMB; } // Reading this takes two cycles (1N+1I), so let's remove them preemptively - gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> currentTimer->prescaleBits); + gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags)); } } void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) { gba->timers[timer].reload = reload; - gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << gba->timers[timer].prescaleBits; + gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << GBATimerFlagsGetPrescaleBits(gba->timers[timer].flags); } void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { struct GBATimer* currentTimer = &gba->timers[timer]; GBATimerUpdateRegister(gba, timer); - int oldPrescale = currentTimer->prescaleBits; + unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags); switch (control & 0x0003) { case 0x0000: - currentTimer->prescaleBits = 0; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 0); break; case 0x0001: - currentTimer->prescaleBits = 6; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 6); break; case 0x0002: - currentTimer->prescaleBits = 8; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 8); break; case 0x0003: - currentTimer->prescaleBits = 10; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 10); break; } - currentTimer->countUp = !!(control & 0x0004); - currentTimer->doIrq = !!(control & 0x0040); - currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits; - int wasEnabled = currentTimer->enable; - currentTimer->enable = !!(control & 0x0080); - if (!wasEnabled && currentTimer->enable) { - if (!currentTimer->countUp) { + currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, control & 0x0004); + currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040); + currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << GBATimerFlagsGetPrescaleBits(currentTimer->flags); + bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags); + currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080); + if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) { + if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval; } else { currentTimer->nextEvent = INT_MAX;@@ -530,12 +530,12 @@ gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
currentTimer->oldReload = currentTimer->reload; currentTimer->lastEvent = gba->cpu->cycles; gba->timersEnabled |= 1 << timer; - } else if (wasEnabled && !currentTimer->enable) { - if (!currentTimer->countUp) { + } else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) { + if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale); } gba->timersEnabled &= ~(1 << timer); - } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) { + } else if (GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) { // FIXME: this might be before present currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval; }
@@ -59,16 +59,19 @@ struct GBAThread;
struct Patch; struct VFile; +DECL_BITFIELD(GBATimerFlags, uint32_t); +DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4); +DECL_BIT(GBATimerFlags, CountUp, 4); +DECL_BIT(GBATimerFlags, DoIrq, 5); +DECL_BIT(GBATimerFlags, Enable, 6); + struct GBATimer { uint16_t reload; uint16_t oldReload; int32_t lastEvent; int32_t nextEvent; int32_t overflowInterval; - unsigned prescaleBits : 4; - unsigned countUp : 1; - unsigned doIrq : 1; - unsigned enable : 1; + GBATimerFlags flags; }; struct GBA {
@@ -156,8 +156,6 @@ GUIMenuItemListInit(&pauseMenu.items, 0);
GUIMenuItemListInit(&stateSaveMenu.items, 9); GUIMenuItemListInit(&stateLoadMenu.items, 9); *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE }; -#if !(defined(__POWERPC__) || defined(__PPC__)) - // PPC doesn't have working savestates yet *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu };@@ -180,7 +178,7 @@ *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_6) };
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_7) }; *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_8) }; *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) }; -#endif + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
@@ -591,41 +591,65 @@
// == Serialization void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) { - state->hw.readWrite = hw->readWrite; - state->hw.pinState = hw->pinState; - state->hw.pinDirection = hw->direction; + GBASerializedHWFlags1 flags1 = 0; + GBASerializedHWFlags2 flags2 = 0; + flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite); + STORE_16(hw->pinState, 0, &state->hw.pinState); + STORE_16(hw->direction, 0, &state->hw.pinDirection); state->hw.devices = hw->devices; - state->hw.rtc = hw->rtc; - state->hw.gyroSample = hw->gyroSample; - state->hw.gyroEdge = hw->gyroEdge; - state->hw.tiltSampleX = hw->tiltX; - state->hw.tiltSampleY = hw->tiltY; - state->hw.tiltState = hw->tiltState; - state->hw.lightCounter = hw->lightCounter; + + STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining); + STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep); + STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead); + STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits); + STORE_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive); + STORE_32(hw->rtc.command, 0, &state->hw.rtc.command); + STORE_32(hw->rtc.control, 0, &state->hw.rtc.control); + memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time)); + + STORE_16(hw->gyroSample, 0, &state->hw.gyroSample); + flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge); + STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX); + STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY); + flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); + flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); state->hw.lightSample = hw->lightSample; - state->hw.lightEdge = hw->lightEdge; - state->hw.gbpInputsPosted = hw->gbpInputsPosted; - state->hw.gbpTxPosition = hw->gbpTxPosition; - state->hw.gbpNextEvent = hw->gbpNextEvent; + flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge); + flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted); + flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition); + STORE_32(hw->gbpNextEvent, 0, &state->hw.gbpNextEvent); + STORE_32(flags1, 0, &state->hw.flags1); + STORE_32(flags2, 0, &state->hw.flags2); } void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) { - hw->readWrite = state->hw.readWrite; - hw->pinState = state->hw.pinState; - hw->direction = state->hw.pinDirection; + GBASerializedHWFlags1 flags1; + LOAD_16(flags1, 0, &state->hw.flags1); + hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1); + LOAD_16(hw->pinState, 0, &state->hw.pinState); + LOAD_16(hw->direction, 0, &state->hw.pinDirection); hw->devices = state->hw.devices; - hw->rtc = state->hw.rtc; - hw->gyroSample = state->hw.gyroSample; - hw->gyroEdge = state->hw.gyroEdge; - hw->tiltX = state->hw.tiltSampleX; - hw->tiltY = state->hw.tiltSampleY; - hw->tiltState = state->hw.tiltState; - hw->lightCounter = state->hw.lightCounter; + + LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining); + LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep); + LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead); + LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits); + LOAD_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive); + LOAD_32(hw->rtc.command, 0, &state->hw.rtc.command); + LOAD_32(hw->rtc.control, 0, &state->hw.rtc.control); + memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time)); + + LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample); + hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1); + LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX); + LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY); + hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2); + hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1); hw->lightSample = state->hw.lightSample; - hw->lightEdge = state->hw.lightEdge; - hw->gbpInputsPosted = state->hw.gbpInputsPosted; - hw->gbpTxPosition = state->hw.gbpTxPosition; - hw->gbpNextEvent = state->hw.gbpNextEvent; + hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1); + hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); + hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); + LOAD_32(hw->gbpNextEvent, 0, &state->hw.gbpNextEvent); if (hw->devices & HW_GB_PLAYER) { GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32); }
@@ -98,7 +98,7 @@ DECL_BITFIELD(GPIOPin, uint16_t);
struct GBACartridgeHardware { struct GBA* p; - int devices; + uint32_t devices; enum GPIODirection readWrite; uint16_t* gpioBase;
@@ -690,21 +690,27 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
int i; for (i = 0; i < REG_MAX; i += 2) { if (_isSpecialRegister[i >> 1]) { - state->io[i >> 1] = gba->memory.io[i >> 1]; + STORE_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { - state->io[i >> 1] = GBAIORead(gba, i); + uint16_t reg = GBAIORead(gba, i); + STORE_16(reg, i, state->io); } } for (i = 0; i < 4; ++i) { - state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1]; - state->dma[i].nextSource = gba->memory.dma[i].nextSource; - state->dma[i].nextDest = gba->memory.dma[i].nextDest; - state->dma[i].nextCount = gba->memory.dma[i].nextCount; - state->dma[i].nextEvent = gba->memory.dma[i].nextEvent; + STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io); + STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload); + STORE_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); + STORE_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + STORE_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent); + STORE_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval); + STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags); + STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); + STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); + STORE_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); + STORE_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent); } - memcpy(state->timers, gba->timers, sizeof(state->timers)); GBAHardwareSerialize(&gba->memory.hw, state); }@@ -712,25 +718,32 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
int i; for (i = 0; i < REG_MAX; i += 2) { if (_isSpecialRegister[i >> 1]) { - gba->memory.io[i >> 1] = state->io[i >> 1]; + LOAD_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { - GBAIOWrite(gba, i, state->io[i >> 1]); + uint16_t reg; + LOAD_16(reg, i, state->io); + GBAIOWrite(gba, i, reg); } } gba->timersEnabled = 0; - memcpy(gba->timers, state->timers, sizeof(gba->timers)); for (i = 0; i < 4; ++i) { - gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1]; - gba->memory.dma[i].nextSource = state->dma[i].nextSource; - gba->memory.dma[i].nextDest = state->dma[i].nextDest; - gba->memory.dma[i].nextCount = state->dma[i].nextCount; - gba->memory.dma[i].nextEvent = state->dma[i].nextEvent; + LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload); + LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); + LOAD_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + LOAD_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent); + LOAD_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval); + LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags); + LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io); + LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); + LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); + LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); + LOAD_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent); if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) { GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]); } - if (gba->timers[i].enable) { + if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { gba->timersEnabled |= 1 << i; } }
@@ -444,13 +444,15 @@
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) { state->savedata.type = savedata->type; state->savedata.command = savedata->command; - state->savedata.flashState = savedata->flashState; - state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000]; - state->savedata.readBitsRemaining = savedata->readBitsRemaining; - state->savedata.readAddress = savedata->readAddress; - state->savedata.writeAddress = savedata->writeAddress; - state->savedata.settlingSector = savedata->settling; - state->savedata.settlingDust = savedata->dust; + GBASerializedSavedataFlags flags = 0; + flags = GBASerializedSavedataFlagsSetFlashState(flags, savedata->flashState); + flags = GBASerializedSavedataFlagsTestFillFlashBank(flags, savedata->currentBank == &savedata->data[0x10000]); + state->savedata.flags = flags; + STORE_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining); + STORE_32(savedata->readAddress, 0, &state->savedata.readAddress); + STORE_32(savedata->writeAddress, 0, &state->savedata.writeAddress); + STORE_16(savedata->settling, 0, &state->savedata.settlingSector); + STORE_16(savedata->dust, 0, &state->savedata.settlingDust); UNUSED(includeData); // TODO }@@ -463,15 +465,16 @@ if (savedata->type != state->savedata.type) {
GBASavedataForceType(savedata, state->savedata.type, savedata->realisticTiming); } savedata->command = state->savedata.command; - savedata->flashState = state->savedata.flashState; - savedata->readBitsRemaining = state->savedata.readBitsRemaining; - savedata->readAddress = state->savedata.readAddress; - savedata->writeAddress = state->savedata.writeAddress; - savedata->settling = state->savedata.settlingSector; - savedata->dust = state->savedata.settlingDust; + GBASerializedSavedataFlags flags = state->savedata.flags; + savedata->flashState = GBASerializedSavedataFlagsGetFlashState(flags); + LOAD_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining); + LOAD_32(savedata->readAddress, 0, &state->savedata.readAddress); + LOAD_32(savedata->writeAddress, 0, &state->savedata.writeAddress); + LOAD_16(savedata->settling, 0, &state->savedata.settlingSector); + LOAD_16(savedata->dust, 0, &state->savedata.settlingDust); if (savedata->type == SAVEDATA_FLASH1M) { - _flashSwitchBank(savedata, state->savedata.flashBank); + _flashSwitchBank(savedata, GBASerializedSavedataFlagsGetFlashBank(flags)); } UNUSED(includeData); // TODO
@@ -25,9 +25,9 @@
const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000; void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { - state->versionMagic = GBA_SAVESTATE_MAGIC; - state->biosChecksum = gba->biosChecksum; - state->romCrc32 = gba->romCrc32; + STORE_32(GBA_SAVESTATE_MAGIC, 0, &state->versionMagic); + STORE_32(gba->biosChecksum, 0, &state->biosChecksum); + STORE_32(gba->romCrc32, 0, &state->romCrc32); if (gba->memory.rom) { state->id = ((struct GBACartridge*) gba->memory.rom)->id;@@ -37,17 +37,25 @@ state->id = 0;
memset(state->title, 0, sizeof(state->title)); } - memcpy(state->cpu.gprs, gba->cpu->gprs, sizeof(state->cpu.gprs)); - state->cpu.cpsr = gba->cpu->cpsr; - state->cpu.spsr = gba->cpu->spsr; - state->cpu.cycles = gba->cpu->cycles; - state->cpu.nextEvent = gba->cpu->nextEvent; - memcpy(state->cpu.bankedRegisters, gba->cpu->bankedRegisters, 6 * 7 * sizeof(int32_t)); - memcpy(state->cpu.bankedSPSRs, gba->cpu->bankedSPSRs, 6 * sizeof(int32_t)); + int i; + for (i = 0; i < 16; ++i) { + STORE_32(gba->cpu->gprs[i], i * sizeof(state->cpu.gprs[0]), state->cpu.gprs); + } + STORE_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed); + STORE_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed); + STORE_32(gba->cpu->cycles, 0, &state->cpu.cycles); + STORE_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent); + for (i = 0; i < 6; ++i) { + int j; + for (j = 0; j < 7; ++j) { + STORE_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters); + } + STORE_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs); + } state->biosPrefetch = gba->memory.biosPrefetch; - state->cpuPrefetch[0] = gba->cpu->prefetch[0]; - state->cpuPrefetch[1] = gba->cpu->prefetch[1]; + STORE_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + STORE_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); GBAMemorySerialize(&gba->memory, state); GBAIOSerialize(gba, state);@@ -63,13 +71,19 @@ }
bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { bool error = false; - if (state->versionMagic != GBA_SAVESTATE_MAGIC) { - GBALog(gba, GBA_LOG_WARN, "Invalid or too new savestate"); + int32_t check; + uint32_t ucheck; + LOAD_32(ucheck, 0, &state->versionMagic); + if (ucheck != GBA_SAVESTATE_MAGIC) { + GBALog(gba, GBA_LOG_WARN, "Invalid or too new savestate: expected %08X, got %08X", GBA_SAVESTATE_MAGIC, ucheck); error = true; } - if (state->biosChecksum != gba->biosChecksum) { - GBALog(gba, GBA_LOG_WARN, "Savestate created using a different version of the BIOS"); - if (state->cpu.gprs[ARM_PC] < SIZE_BIOS && state->cpu.gprs[ARM_PC] >= 0x20) { + LOAD_32(ucheck, 0, &state->biosChecksum); + if (ucheck != gba->biosChecksum) { + GBALog(gba, GBA_LOG_WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck); + uint32_t pc; + LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); + if (pc < SIZE_BIOS && pc >= 0x20) { error = true; } }@@ -80,46 +94,60 @@ } else if (!gba->memory.rom && state->id != 0) {
GBALog(gba, GBA_LOG_WARN, "Savestate is for a game, but no game loaded"); error = true; } - if (state->romCrc32 != gba->romCrc32) { + LOAD_32(ucheck, 0, &state->romCrc32); + if (ucheck != gba->romCrc32) { GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game"); } - if (state->cpu.cycles < 0) { + LOAD_32(check, 0, &state->cpu.cycles); + if (check < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are negative"); error = true; } - if (state->cpu.cycles >= (int32_t) GBA_ARM7TDMI_FREQUENCY) { + if (check >= (int32_t) GBA_ARM7TDMI_FREQUENCY) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are too high"); error = true; } - if (state->video.eventDiff < 0) { + LOAD_32(check, 0, &state->video.eventDiff); + if (check < 0) { GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: video eventDiff is negative"); error = true; } - int region = (state->cpu.gprs[ARM_PC] >> BASE_OFFSET); - if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((state->cpu.gprs[ARM_PC] - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { + LOAD_32(check, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); + int region = (check >> BASE_OFFSET); + if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((check - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { GBALog(gba, GBA_LOG_WARN, "Savestate created using a differently sized version of the ROM"); error = true; } if (error) { return false; } - memcpy(gba->cpu->gprs, state->cpu.gprs, sizeof(gba->cpu->gprs)); - gba->cpu->cpsr = state->cpu.cpsr; - gba->cpu->spsr = state->cpu.spsr; - gba->cpu->cycles = state->cpu.cycles; - gba->cpu->nextEvent = state->cpu.nextEvent; - memcpy(gba->cpu->bankedRegisters, state->cpu.bankedRegisters, 6 * 7 * sizeof(int32_t)); - memcpy(gba->cpu->bankedSPSRs, state->cpu.bankedSPSRs, 6 * sizeof(int32_t)); + size_t i; + for (i = 0; i < 16; ++i) { + LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs); + } + LOAD_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed); + LOAD_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed); + LOAD_32(gba->cpu->cycles, 0, &state->cpu.cycles); + LOAD_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent); + for (i = 0; i < 6; ++i) { + int j; + for (j = 0; j < 7; ++j) { + LOAD_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters); + } + LOAD_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs); + } gba->cpu->privilegeMode = gba->cpu->cpsr.priv; gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); if (state->biosPrefetch) { - gba->memory.biosPrefetch = state->biosPrefetch; + LOAD_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch); } if (gba->cpu->cpsr.t) { gba->cpu->executionMode = MODE_THUMB; if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) { - gba->cpu->prefetch[0] = state->cpuPrefetch[0] & 0xFFFF; - gba->cpu->prefetch[1] = state->cpuPrefetch[1] & 0xFFFF; + LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); + gba->cpu->prefetch[0] &= 0xFFFF; + gba->cpu->prefetch[1] &= 0xFFFF; } else { // Maintain backwards compat LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);@@ -128,8 +156,8 @@ }
} else { gba->cpu->executionMode = MODE_ARM; if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) { - gba->cpu->prefetch[0] = state->cpuPrefetch[0]; - gba->cpu->prefetch[1] = state->cpuPrefetch[1]; + LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); } else { // Maintain backwards compat LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);@@ -245,10 +273,39 @@ }
bool success = GBASaveStateNamed(threadContext->gba, vf, screenshot); vf->close(vf); if (success) { +#if SAVESTATE_DEBUG + vf = GBAGetState(threadContext->gba, dir, slot, false); + if (vf) { + struct GBA* backup = anonymousMemoryMap(sizeof(*backup)); + memcpy(backup, threadContext->gba, sizeof(*backup)); + memset(threadContext->gba->memory.io, 0, sizeof(threadContext->gba->memory.io)); + memset(threadContext->gba->timers, 0, sizeof(threadContext->gba->timers)); + GBALoadStateNamed(threadContext->gba, vf); + if (memcmp(backup, threadContext->gba, sizeof(*backup))) { + char suffix[16] = { '\0' }; + struct VFile* vf2; + snprintf(suffix, sizeof(suffix), ".dump.0.%d", slot); + vf2 = VDirOptionalOpenFile(dir, threadContext->gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); + if (vf2) { + vf2->write(vf2, backup, sizeof(*backup)); + vf2->close(vf2); + } + snprintf(suffix, sizeof(suffix), ".dump.1.%d", slot); + vf2 = VDirOptionalOpenFile(dir, threadContext->gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); + if (vf2) { + vf2->write(vf2, threadContext->gba, sizeof(*threadContext->gba)); + vf2->close(vf2); + } + } + mappedMemoryFree(backup, sizeof(*backup)); + vf->close(vf); + } +#endif GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i saved", slot); } else { GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to save", slot); } + return success; }
@@ -184,6 +184,33 @@ * 0x21000 - 0x60FFF: WRAM
* Total size: 0x61000 (397,312) bytes */ +DECL_BITFIELD(GBASerializedAudioFlags, uint32_t); +DECL_BITS(GBASerializedAudioFlags, Ch1Volume, 0, 4); +DECL_BIT(GBASerializedAudioFlags, Ch1Dead, 4); +DECL_BIT(GBASerializedAudioFlags, Ch1Hi, 5); +DECL_BITS(GBASerializedAudioFlags, Ch2Volume, 8, 4); +DECL_BIT(GBASerializedAudioFlags, Ch2Dead, 12); +DECL_BIT(GBASerializedAudioFlags, Ch2Hi, 13); +DECL_BITS(GBASerializedAudioFlags, Ch4Volume, 16, 4); +DECL_BIT(GBASerializedAudioFlags, Ch4Dead, 20); + +DECL_BITFIELD(GBASerializedHWFlags1, uint16_t); +DECL_BIT(GBASerializedHWFlags1, ReadWrite, 0); +DECL_BIT(GBASerializedHWFlags1, GyroEdge, 1); +DECL_BIT(GBASerializedHWFlags1, LightEdge, 2); +DECL_BITS(GBASerializedHWFlags1, LightCounter, 4, 12); + +DECL_BITFIELD(GBASerializedHWFlags2, uint8_t); +DECL_BITS(GBASerializedHWFlags2, TiltState, 0, 2); +DECL_BITS(GBASerializedHWFlags2, GbpInputsPosted, 2, 2); +DECL_BITS(GBASerializedHWFlags2, GbpTxPosition, 4, 5); + +DECL_BITFIELD(GBASerializedHWFlags3, uint16_t); + +DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t); +DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2); +DECL_BIT(GBASerializedSavedataFlags, FlashBank, 4); + struct GBASerializedState { uint32_t versionMagic; uint32_t biosChecksum;@@ -236,18 +263,7 @@ int32_t nextEvent;
int32_t eventDiff; int32_t nextSample; uint32_t fifoSize; - unsigned ch1Volume : 4; - unsigned ch1Dead : 1; - unsigned ch1Hi : 1; - unsigned : 2; - unsigned ch2Volume : 4; - unsigned ch2Dead : 1; - unsigned ch2Hi : 1; - unsigned : 2; - unsigned ch4Volume : 4; - unsigned ch4Dead : 1; - unsigned : 3; - unsigned : 8; + GBASerializedAudioFlags flags; } audio; struct {@@ -275,33 +291,23 @@ uint16_t pinState;
uint16_t pinDirection; struct GBARTC rtc; uint8_t devices; - // Do not change these to uint16_t, this breaks bincompat with some older compilers - unsigned gyroSample : 16; - unsigned tiltSampleX : 16; - unsigned tiltSampleY : 16; - unsigned readWrite : 1; - unsigned gyroEdge : 1; - unsigned lightEdge : 1; - unsigned : 1; - unsigned lightCounter : 12; - unsigned lightSample : 8; - unsigned tiltState : 2; - unsigned gbpInputsPosted : 2; - unsigned gbpTxPosition : 5; - unsigned : 15; - uint32_t gbpNextEvent : 32; + uint16_t gyroSample; + uint16_t tiltSampleX; + uint16_t tiltSampleY; + GBASerializedHWFlags1 flags1; + uint8_t lightSample; + GBASerializedHWFlags2 flags2; + GBASerializedHWFlags3 flags3; + uint32_t gbpNextEvent; } hw; uint32_t reservedHardware[6]; struct { - unsigned type : 8; - unsigned command : 8; - unsigned flashState : 2; - unsigned : 2; - unsigned flashBank : 1; - unsigned : 3; - unsigned : 8; + uint8_t type; + uint8_t command; + GBASerializedSavedataFlags flags; + uint8_t reserved; int32_t readBitsRemaining; uint32_t readAddress; uint32_t writeAddress;
@@ -274,14 +274,13 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state) {
memcpy(state->vram, video->renderer->vram, SIZE_VRAM); memcpy(state->oam, video->oam.raw, SIZE_OAM); memcpy(state->pram, video->palette, SIZE_PALETTE_RAM); - state->video.nextEvent = video->nextEvent; - state->video.eventDiff = video->eventDiff; - state->video.lastHblank = video->nextHblank - VIDEO_HBLANK_LENGTH; - state->video.nextHblank = video->nextHblank; - state->video.nextHblankIRQ = video->nextHblankIRQ; - state->video.nextVblankIRQ = video->nextVblankIRQ; - state->video.nextVcounterIRQ = video->nextVcounterIRQ; - state->video.frameCounter = video->frameCounter; + STORE_32(video->nextEvent, 0, &state->video.nextEvent); + STORE_32(video->eventDiff, 0, &state->video.eventDiff); + STORE_32(video->nextHblank, 0, &state->video.nextHblank); + STORE_32(video->nextHblankIRQ, 0, &state->video.nextHblankIRQ); + STORE_32(video->nextVblankIRQ, 0, &state->video.nextVblankIRQ); + STORE_32(video->nextVcounterIRQ, 0, &state->video.nextVcounterIRQ); + STORE_32(video->frameCounter, 0, &state->video.frameCounter); } void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state) {@@ -296,12 +295,12 @@ for (i = 0; i < SIZE_PALETTE_RAM; i += 2) {
LOAD_16(value, i, state->pram); GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0); } - video->nextEvent = state->video.nextEvent; - video->eventDiff = state->video.eventDiff; - video->nextHblank = state->video.nextHblank; - video->nextHblankIRQ = state->video.nextHblankIRQ; - video->nextVblankIRQ = state->video.nextVblankIRQ; - video->nextVcounterIRQ = state->video.nextVcounterIRQ; - video->frameCounter = state->video.frameCounter; - video->vcount = state->io[REG_VCOUNT >> 1]; + LOAD_32(video->nextEvent, 0, &state->video.nextEvent); + LOAD_32(video->eventDiff, 0, &state->video.eventDiff); + LOAD_32(video->nextHblank, 0, &state->video.nextHblank); + LOAD_32(video->nextHblankIRQ, 0, &state->video.nextHblankIRQ); + LOAD_32(video->nextVblankIRQ, 0, &state->video.nextVblankIRQ); + LOAD_32(video->nextVcounterIRQ, 0, &state->video.nextVcounterIRQ); + LOAD_32(video->frameCounter, 0, &state->video.frameCounter); + LOAD_16(video->vcount, REG_VCOUNT, state->io); }
@@ -86,6 +86,7 @@ #define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1))
#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END))) #define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END)) #define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END)) +#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END))) #ifdef _MSC_VER #define ATTRIBUTE_UNUSED@@ -112,6 +113,9 @@ return FILL_BITS(src, (START), (START) + (SIZE)); \
} \ ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \ return INS_BITS(src, (START), (START) + (SIZE), bits); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## TestFill ## FIELD (TYPE src, bool test) { \ + return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \ } #define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1)