예제 #1
0
파일: serialize.c 프로젝트: leiradel/mgba
void GBSGBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
	gb->video.sgbCommandHeader = state->sgb.command;
	gb->sgbBit = state->sgb.bits;

	GBSerializedSGBFlags flags;
	LOAD_32LE(flags, 0, &state->sgb.flags);
	gb->currentSgbBits = GBSerializedSGBFlagsGetP1Bits(flags);
	gb->video.renderer->sgbRenderMode = GBSerializedSGBFlagsGetRenderMode(flags);
	gb->video.sgbBufferIndex = GBSerializedSGBFlagsGetBufferIndex(flags);
	gb->sgbControllers = GBSerializedSGBFlagsGetReqControllers(flags);
	gb->sgbCurrentController = GBSerializedSGBFlagsGetCurrentController(flags);

	memcpy(gb->video.sgbPacketBuffer, state->sgb.packet, sizeof(state->sgb.packet));
	memcpy(gb->sgbPacket, state->sgb.inProgressPacket, sizeof(state->sgb.inProgressPacket));

	if (!gb->video.renderer->sgbCharRam) {
		gb->video.renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
	}
	if (!gb->video.renderer->sgbMapRam) {
		gb->video.renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
	}
	if (!gb->video.renderer->sgbPalRam) {
		gb->video.renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
	}
	if (!gb->video.renderer->sgbAttributeFiles) {
		gb->video.renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
	}
	if (!gb->video.renderer->sgbAttributes) {
		gb->video.renderer->sgbAttributes = malloc(90 * 45);
	}

	memcpy(gb->video.renderer->sgbCharRam, state->sgb.charRam, sizeof(state->sgb.charRam));
	memcpy(gb->video.renderer->sgbMapRam, state->sgb.mapRam, sizeof(state->sgb.mapRam));
	memcpy(gb->video.renderer->sgbPalRam, state->sgb.palRam, sizeof(state->sgb.palRam));
	memcpy(gb->video.renderer->sgbAttributeFiles, state->sgb.atfRam, sizeof(state->sgb.atfRam));
	memcpy(gb->video.renderer->sgbAttributes, state->sgb.attributes, sizeof(state->sgb.attributes));

	GBVideoWriteSGBPacket(&gb->video, (uint8_t[16]) { (SGB_ATRC_EN << 3) | 1, 0 });
}
예제 #2
0
파일: serialize.c 프로젝트: Bizcocho/mgba
bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
	bool error = false;
	int32_t check;
	uint32_t ucheck;
	LOAD_32LE(ucheck, 0, &state->versionMagic);
	if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
		mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
		error = true;
	} else if (ucheck < GB_SAVESTATE_MAGIC) {
		mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
		error = true;
	} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
		mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
	}

	if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
		mLOG(GB_STATE, WARN, "Savestate is for a different game");
		error = true;
	}
	LOAD_32LE(ucheck, 0, &state->romCrc32);
	if (ucheck != gb->romCrc32) {
		mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
	}
	LOAD_32LE(check, 0, &state->cpu.cycles);
	if (check < 0) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
		error = true;
	}
	if (check >= (int32_t) DMG_LR35902_FREQUENCY) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
		error = true;
	}
	LOAD_32LE(check, 0, &state->video.eventDiff);
	if (check < 0) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: video eventDiff is negative");
		error = true;
	}
	if (error) {
		return false;
	}

	gb->cpu->a = state->cpu.a;
	gb->cpu->f.packed = state->cpu.f;
	gb->cpu->b = state->cpu.b;
	gb->cpu->c = state->cpu.c;
	gb->cpu->d = state->cpu.d;
	gb->cpu->e = state->cpu.e;
	gb->cpu->h = state->cpu.h;
	gb->cpu->l = state->cpu.l;
	LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
	LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);

	LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
	gb->cpu->bus = state->cpu.bus;
	gb->cpu->executionState = state->cpu.executionState;
	LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);

	LOAD_32LE(gb->eiPending, 0, &state->cpu.eiPending);

	GBSerializedCpuFlags flags;
	LOAD_32LE(flags, 0, &state->cpu.flags);
	gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
	gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
	gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);

	LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
	LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);

	gb->model = state->model;

	if (gb->model < GB_MODEL_CGB) {
		gb->audio.style = GB_AUDIO_DMG;
	} else {
		gb->audio.style = GB_AUDIO_CGB;
	}

	GBMemoryDeserialize(&gb->memory, state);
	GBIODeserialize(gb, state);
	GBVideoDeserialize(&gb->video, state);
	GBTimerDeserialize(&gb->timer, state);
	GBAudioDeserialize(&gb->audio, state);

	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);

	return true;
}
예제 #3
0
파일: serialize.c 프로젝트: leiradel/mgba
bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
	bool error = false;
	int32_t check;
	uint32_t ucheck;
	int16_t check16;
	uint16_t ucheck16;
	LOAD_32LE(ucheck, 0, &state->versionMagic);
	if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
		mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
		error = true;
	} else if (ucheck < GB_SAVESTATE_MAGIC) {
		mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
		error = true;
	} else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) {
		mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck);
	}
	bool canSgb = ucheck >= GB_SAVESTATE_MAGIC + 2;

	if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) &gb->memory.rom[0x100])->titleLong, sizeof(state->title))) {
		LOAD_32LE(ucheck, 0, &state->versionMagic);
		if (ucheck > GB_SAVESTATE_MAGIC + 2 || memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) {
			// There was a bug in previous versions where the memory address being compared was wrong
			mLOG(GB_STATE, WARN, "Savestate is for a different game");
			error = true;
		}
	}
	LOAD_32LE(ucheck, 0, &state->romCrc32);
	if (ucheck != gb->romCrc32) {
		mLOG(GB_STATE, WARN, "Savestate is for a different version of the game");
	}
	LOAD_32LE(check, 0, &state->cpu.cycles);
	if (check < 0) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
		error = true;
	}
	if (state->cpu.executionState != LR35902_CORE_FETCH) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: Execution state is not FETCH");
		error = true;
	}
	if (check >= (int32_t) DMG_LR35902_FREQUENCY) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
		error = true;
	}
	LOAD_16LE(check16, 0, &state->video.x);
	if (check16 < 0 || check16 > GB_VIDEO_HORIZONTAL_PIXELS) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: video x is out of range");
		error = true;
	}
	LOAD_16LE(check16, 0, &state->video.ly);
	if (check16 < 0 || check16 > GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: video y is out of range");
		error = true;
	}
	LOAD_16LE(ucheck16, 0, &state->memory.dmaDest);
	if (ucheck16 + state->memory.dmaRemaining > GB_SIZE_OAM) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: DMA destination is out of range");
		error = true;
	}
	LOAD_16LE(ucheck16, 0, &state->video.bcpIndex);
	if (ucheck16 >= 0x40) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: BCPS is out of range");
	}
	LOAD_16LE(ucheck16, 0, &state->video.ocpIndex);
	if (ucheck16 >= 0x40) {
		mLOG(GB_STATE, WARN, "Savestate is corrupted: OCPS is out of range");
	}
	if (error) {
		return false;
	}
	gb->timing.root = NULL;
	LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles);

	gb->cpu->a = state->cpu.a;
	gb->cpu->f.packed = state->cpu.f;
	gb->cpu->b = state->cpu.b;
	gb->cpu->c = state->cpu.c;
	gb->cpu->d = state->cpu.d;
	gb->cpu->e = state->cpu.e;
	gb->cpu->h = state->cpu.h;
	gb->cpu->l = state->cpu.l;
	LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp);
	LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc);

	LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
	gb->cpu->bus = state->cpu.bus;
	gb->cpu->executionState = state->cpu.executionState;

	GBSerializedCpuFlags flags;
	LOAD_32LE(flags, 0, &state->cpu.flags);
	gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
	gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
	gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
	gb->audio.timingFactor = gb->doubleSpeed + 1;

	LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
	LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
	gb->timing.root = NULL;

	uint32_t when;
	LOAD_32LE(when, 0, &state->cpu.eiPending);
	if (GBSerializedCpuFlagsIsEiPending(flags)) {
		mTimingSchedule(&gb->timing, &gb->eiPending, when);
	}

	gb->model = state->model;

	if (gb->model < GB_MODEL_CGB) {
		gb->audio.style = GB_AUDIO_DMG;
	} else {
		gb->audio.style = GB_AUDIO_CGB;
	}

	GBMemoryDeserialize(gb, state);
	GBVideoDeserialize(&gb->video, state);
	GBIODeserialize(gb, state);
	GBTimerDeserialize(&gb->timer, state);
	GBAudioDeserialize(&gb->audio, state);

	if (gb->model & GB_MODEL_SGB && canSgb) {
		GBSGBDeserialize(gb, state);
	}

	gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);

	gb->timing.reroot = gb->timing.root;
	gb->timing.root = NULL;

	return true;
}
예제 #4
0
파일: memory.c 프로젝트: OpenEmu/mGBA-Core
void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
	struct GBMemory* memory = &gb->memory;
	memcpy(memory->wram, state->wram, GB_SIZE_WORKING_RAM);
	memcpy(memory->hram, state->hram, GB_SIZE_HRAM);
	LOAD_16LE(memory->currentBank, 0, &state->memory.currentBank);
	memory->wramCurrentBank = state->memory.wramCurrentBank;
	memory->sramCurrentBank = state->memory.sramCurrentBank;

	GBMBCSwitchBank(gb, memory->currentBank);
	GBMemorySwitchWramBank(memory, memory->wramCurrentBank);
	GBMBCSwitchSramBank(gb, memory->sramCurrentBank);

	LOAD_16LE(memory->dmaSource, 0, &state->memory.dmaSource);
	LOAD_16LE(memory->dmaDest, 0, &state->memory.dmaDest);

	LOAD_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource);
	LOAD_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest);

	LOAD_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining);
	memory->dmaRemaining = state->memory.dmaRemaining;
	memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs));

	uint32_t when;
	LOAD_32LE(when, 0, &state->memory.dmaNext);
	if (memory->dmaRemaining) {
		mTimingSchedule(&gb->timing, &memory->dmaEvent, when);
	}
	LOAD_32LE(when, 0, &state->memory.hdmaNext);
	if (memory->hdmaRemaining) {
		mTimingSchedule(&gb->timing, &memory->hdmaEvent, when);
	}

	GBSerializedMemoryFlags flags;
	LOAD_16LE(flags, 0, &state->memory.flags);
	memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags);
	memory->rtcAccess = GBSerializedMemoryFlagsGetRtcAccess(flags);
	memory->rtcLatched = GBSerializedMemoryFlagsGetRtcLatched(flags);
	memory->ime = GBSerializedMemoryFlagsGetIme(flags);
	memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags);
	memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);

	switch (memory->mbcType) {
	case GB_MBC1:
		memory->mbcState.mbc1.mode = state->memory.mbc1.mode;
		memory->mbcState.mbc1.multicartStride = state->memory.mbc1.multicartStride;
		if (memory->mbcState.mbc1.mode) {
			GBMBCSwitchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride);
		}
		break;
	case GB_MBC3_RTC:
		LOAD_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch);
		break;
	case GB_MBC7:
		memory->mbcState.mbc7.state = state->memory.mbc7.state;
		memory->mbcState.mbc7.eeprom = state->memory.mbc7.eeprom;
		memory->mbcState.mbc7.address = state->memory.mbc7.address & 0x7F;
		memory->mbcState.mbc7.access = state->memory.mbc7.access;
		memory->mbcState.mbc7.latch = state->memory.mbc7.latch;
		memory->mbcState.mbc7.srBits = state->memory.mbc7.srBits;
		LOAD_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr);
		LOAD_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable);
		break;
	default:
		break;
	}