void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) { const struct GBMemory* memory = &gb->memory; memcpy(state->wram, memory->wram, GB_SIZE_WORKING_RAM); memcpy(state->hram, memory->hram, GB_SIZE_HRAM); STORE_16LE(memory->currentBank, 0, &state->memory.currentBank); state->memory.wramCurrentBank = memory->wramCurrentBank; state->memory.sramCurrentBank = memory->sramCurrentBank; STORE_16LE(memory->dmaSource, 0, &state->memory.dmaSource); STORE_16LE(memory->dmaDest, 0, &state->memory.dmaDest); STORE_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource); STORE_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest); STORE_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining); state->memory.dmaRemaining = memory->dmaRemaining; memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs)); STORE_32LE(memory->dmaEvent.when - mTimingCurrentTime(&gb->timing), 0, &state->memory.dmaNext); STORE_32LE(memory->hdmaEvent.when - mTimingCurrentTime(&gb->timing), 0, &state->memory.hdmaNext); GBSerializedMemoryFlags flags = 0; flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess); flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess); flags = GBSerializedMemoryFlagsSetRtcLatched(flags, memory->rtcLatched); flags = GBSerializedMemoryFlagsSetIme(flags, memory->ime); flags = GBSerializedMemoryFlagsSetIsHdma(flags, memory->isHdma); flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg); STORE_16LE(flags, 0, &state->memory.flags); switch (memory->mbcType) { case GB_MBC1: state->memory.mbc1.mode = memory->mbcState.mbc1.mode; state->memory.mbc1.multicartStride = memory->mbcState.mbc1.multicartStride; break; case GB_MBC3_RTC: STORE_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch); break; case GB_MBC7: state->memory.mbc7.state = memory->mbcState.mbc7.state; state->memory.mbc7.eeprom = memory->mbcState.mbc7.eeprom; state->memory.mbc7.address = memory->mbcState.mbc7.address; state->memory.mbc7.access = memory->mbcState.mbc7.access; state->memory.mbc7.latch = memory->mbcState.mbc7.latch; state->memory.mbc7.srBits = memory->mbcState.mbc7.srBits; STORE_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr); STORE_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable); break; default: break; } }
// TODO: Reorganize SGB into its own file void GBSGBSerialize(struct GB* gb, struct GBSerializedState* state) { state->sgb.command = gb->video.sgbCommandHeader; state->sgb.bits = gb->sgbBit; GBSerializedSGBFlags flags = 0; flags = GBSerializedSGBFlagsSetP1Bits(flags, gb->currentSgbBits); flags = GBSerializedSGBFlagsSetRenderMode(flags, gb->video.renderer->sgbRenderMode); flags = GBSerializedSGBFlagsSetBufferIndex(flags, gb->video.sgbBufferIndex); flags = GBSerializedSGBFlagsSetReqControllers(flags, gb->sgbControllers); flags = GBSerializedSGBFlagsSetCurrentController(flags, gb->sgbCurrentController); STORE_32LE(flags, 0, &state->sgb.flags); memcpy(state->sgb.packet, gb->video.sgbPacketBuffer, sizeof(state->sgb.packet)); memcpy(state->sgb.inProgressPacket, gb->sgbPacket, sizeof(state->sgb.inProgressPacket)); if (gb->video.renderer->sgbCharRam) { memcpy(state->sgb.charRam, gb->video.renderer->sgbCharRam, sizeof(state->sgb.charRam)); } if (gb->video.renderer->sgbMapRam) { memcpy(state->sgb.mapRam, gb->video.renderer->sgbMapRam, sizeof(state->sgb.mapRam)); } if (gb->video.renderer->sgbPalRam) { memcpy(state->sgb.palRam, gb->video.renderer->sgbPalRam, sizeof(state->sgb.palRam)); } if (gb->video.renderer->sgbAttributeFiles) { memcpy(state->sgb.atfRam, gb->video.renderer->sgbAttributeFiles, sizeof(state->sgb.atfRam)); } if (gb->video.renderer->sgbAttributes) { memcpy(state->sgb.attributes, gb->video.renderer->sgbAttributes, sizeof(state->sgb.attributes)); } gb->video.renderer->enableSGBBorder(gb->video.renderer, gb->video.sgbBorders); }
ssize_t VFileRead32LE(struct VFile* vf, void* word) { uint32_t leword; ssize_t r = vf->read(vf, &leword, 4); if (r == 4) { STORE_32LE(leword, 0, word); } return r; }
void GBSerialize(struct GB* gb, struct GBSerializedState* state) { STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32LE(gb->romCrc32, 0, &state->romCrc32); STORE_32LE(gb->timing.masterCycles, 0, &state->masterCycles); if (gb->memory.rom) { memcpy(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title)); } else { memset(state->title, 0, sizeof(state->title)); } state->model = gb->model; state->cpu.a = gb->cpu->a; state->cpu.f = gb->cpu->f.packed; state->cpu.b = gb->cpu->b; state->cpu.c = gb->cpu->c; state->cpu.d = gb->cpu->d; state->cpu.e = gb->cpu->e; state->cpu.h = gb->cpu->h; state->cpu.l = gb->cpu->l; STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp); STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc); STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); STORE_16LE(gb->cpu->index, 0, &state->cpu.index); state->cpu.bus = gb->cpu->bus; state->cpu.executionState = gb->cpu->executionState; GBSerializedCpuFlags flags = 0; flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending); flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed); flags = GBSerializedCpuFlagsSetEiPending(flags, mTimingIsScheduled(&gb->timing, &gb->eiPending)); STORE_32LE(flags, 0, &state->cpu.flags); STORE_32LE(gb->eiPending.when - mTimingCurrentTime(&gb->timing), 0, &state->cpu.eiPending); GBMemorySerialize(gb, state); GBIOSerialize(gb, state); GBVideoSerialize(&gb->video, state); GBTimerSerialize(&gb->timer, state); GBAudioSerialize(&gb->audio, state); if (gb->model & GB_MODEL_SGB) { GBSGBSerialize(gb, state); } }
ssize_t VFileWrite32LE(struct VFile* vf, int32_t word) { uint32_t leword; STORE_32LE(word, 0, &leword); return vf->write(vf, &leword, 4); }
void GBSerialize(struct GB* gb, struct GBSerializedState* state) { STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic); STORE_32LE(gb->romCrc32, 0, &state->romCrc32); if (gb->memory.rom) { memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title)); } else { memset(state->title, 0, sizeof(state->title)); } state->model = gb->model; state->cpu.a = gb->cpu->a; state->cpu.f = gb->cpu->f.packed; state->cpu.b = gb->cpu->b; state->cpu.c = gb->cpu->c; state->cpu.d = gb->cpu->d; state->cpu.e = gb->cpu->e; state->cpu.h = gb->cpu->h; state->cpu.l = gb->cpu->l; STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp); STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc); STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); STORE_16LE(gb->cpu->index, 0, &state->cpu.index); state->cpu.bus = gb->cpu->bus; state->cpu.executionState = gb->cpu->executionState; STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); STORE_32LE(gb->eiPending, 0, &state->cpu.eiPending); GBSerializedCpuFlags flags = 0; flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending); flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed); STORE_32LE(flags, 0, &state->cpu.flags); GBMemorySerialize(&gb->memory, state); GBIOSerialize(gb, state); GBVideoSerialize(&gb->video, state); GBTimerSerialize(&gb->timer, state); GBAudioSerialize(&gb->audio, state); #ifndef _MSC_VER struct timeval tv; if (!gettimeofday(&tv, 0)) { uint64_t usec = tv.tv_usec; usec += tv.tv_sec * 1000000LL; STORE_64LE(usec, 0, &state->creationUsec); } #else struct timespec ts; if (timespec_get(&ts, TIME_UTC)) { uint64_t usec = ts.tv_nsec / 1000; usec += ts.tv_sec * 1000000LL; STORE_64LE(usec, 0, &state->creationUsec); } #endif else { state->creationUsec = 0; } }