int S9xUnfreezeFromStream()

in cores/snes/snapshot.cpp [1403:1826]


int S9xUnfreezeFromStream (STREAM stream)
{
	int		result = SUCCESS;
	int		version, len;
	char	buffer[PATH_MAX + 1];

	len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1;
	if (READ_STREAM(buffer, len, stream) != len)
		return (WRONG_FORMAT);

	if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0)
		return (WRONG_FORMAT);

	version = atoi(&buffer[strlen(SNAPSHOT_MAGIC) + 1]);
	if (version > SNAPSHOT_VERSION)
		return (WRONG_VERSION);

	result = UnfreezeBlock(stream, "NAM", (uint8 *) buffer, PATH_MAX);
	if (result != SUCCESS)
		return (result);

	uint8	*local_cpu           = NULL;
	uint8	*local_registers     = NULL;
	uint8	*local_ppu           = NULL;
	uint8	*local_dma           = NULL;
	uint8	*local_vram          = NULL;
	uint8	*local_ram           = NULL;
	uint8	*local_sram          = NULL;
	uint8	*local_fillram       = NULL;
	uint8	*local_apu_sound     = NULL;
	uint8	*local_control_data  = NULL;
	uint8	*local_timing_data   = NULL;
	uint8	*local_superfx       = NULL;
	uint8	*local_sa1           = NULL;
	uint8	*local_sa1_registers = NULL;
	uint8	*local_dsp1          = NULL;
	uint8	*local_dsp2          = NULL;
	uint8	*local_dsp4          = NULL;
	uint8	*local_cx4_data      = NULL;
	uint8	*local_st010         = NULL;
	uint8	*local_obc1          = NULL;
	uint8	*local_obc1_data     = NULL;
	uint8	*local_spc7110       = NULL;
	uint8	*local_srtc          = NULL;
	uint8	*local_rtc_data      = NULL;
	uint8	*local_bsx_data      = NULL;
	uint8	*local_msu1_data      = NULL;
	uint8	*local_screenshot    = NULL;
	uint8	*local_movie_data    = NULL;

	do
	{
		result = UnfreezeStructCopy(stream, "CPU", &local_cpu, SnapCPU, COUNT(SnapCPU), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "REG", &local_registers, SnapRegisters, COUNT(SnapRegisters), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "PPU", &local_ppu, SnapPPU, COUNT(SnapPPU), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "DMA", &local_dma, SnapDMA, COUNT(SnapDMA), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeBlockCopy (stream, "VRA", &local_vram, 0x10000);
		if (result != SUCCESS)
			break;

		result = UnfreezeBlockCopy (stream, "RAM", &local_ram, 0x20000);
		if (result != SUCCESS)
			break;

		result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000);
		if (result != SUCCESS)
			break;

		result = UnfreezeBlockCopy (stream, "FIL", &local_fillram, 0x8000);
		if (result != SUCCESS)
			break;

		result = UnfreezeBlockCopy (stream, "SND", &local_apu_sound, SPC_SAVE_STATE_BLOCK_SIZE);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "CTL", &local_control_data, SnapControls, COUNT(SnapControls), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "TIM", &local_timing_data, SnapTimings, COUNT(SnapTimings), version);
		if (result != SUCCESS)
			break;

		result = UnfreezeStructCopy(stream, "SFX", &local_superfx, SnapFX, COUNT(SnapFX), version);
		if (result != SUCCESS && Settings.SuperFX)
			break;

		result = UnfreezeStructCopy(stream, "SA1", &local_sa1, SnapSA1, COUNT(SnapSA1), version);
		if (result != SUCCESS && Settings.SA1)
			break;

		result = UnfreezeStructCopy(stream, "SAR", &local_sa1_registers, SnapSA1Registers, COUNT(SnapSA1Registers), version);
		if (result != SUCCESS && Settings.SA1)
			break;

		result = UnfreezeStructCopy(stream, "DP1", &local_dsp1, SnapDSP1, COUNT(SnapDSP1), version);
		if (result != SUCCESS && Settings.DSP == 1)
			break;

		result = UnfreezeStructCopy(stream, "DP2", &local_dsp2, SnapDSP2, COUNT(SnapDSP2), version);
		if (result != SUCCESS && Settings.DSP == 2)
			break;

		result = UnfreezeStructCopy(stream, "DP4", &local_dsp4, SnapDSP4, COUNT(SnapDSP4), version);
		if (result != SUCCESS && Settings.DSP == 4)
			break;

		result = UnfreezeBlockCopy (stream, "CX4", &local_cx4_data, 8192);
		if (result != SUCCESS && Settings.C4)
			break;

		result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version);
		if (result != SUCCESS && Settings.SETA == ST_010)
			break;

		result = UnfreezeStructCopy(stream, "OBC", &local_obc1, SnapOBC1, COUNT(SnapOBC1), version);
		if (result != SUCCESS && Settings.OBC1)
			break;

		result = UnfreezeBlockCopy (stream, "OBM", &local_obc1_data, 8192);
		if (result != SUCCESS && Settings.OBC1)
			break;

		result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version);
		if (result != SUCCESS && Settings.SPC7110)
			break;

		result = UnfreezeStructCopy(stream, "SRT", &local_srtc, SnapSRTCSnap, COUNT(SnapSRTCSnap), version);
		if (result != SUCCESS && Settings.SRTC)
			break;

		result = UnfreezeBlockCopy (stream, "CLK", &local_rtc_data, 20);
		if (result != SUCCESS && (Settings.SRTC || Settings.SPC7110RTC))
			break;

		result = UnfreezeStructCopy(stream, "BSX", &local_bsx_data, SnapBSX, COUNT(SnapBSX), version);
		if (result != SUCCESS && Settings.BS)
			break;

		result = UnfreezeStructCopy(stream, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version);
		if (result != SUCCESS && Settings.MSU1)
			break;

		result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version);

		SnapshotMovieInfo	mi;

		result = UnfreezeStruct(stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie), version);
		if (result == SUCCESS)
			result = UnfreezeBlockCopy(stream, "MID", &local_movie_data, mi.MovieInputDataSize);

		result = SUCCESS;
	} while (false);

	if (result == SUCCESS)
	{
		uint32 old_flags     = CPU.Flags;
		uint32 sa1_old_flags = SA1.Flags;

		S9xReset();

		UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version);

		UnfreezeStructFromCopy(&Registers, SnapRegisters, COUNT(SnapRegisters), local_registers, version);

		UnfreezeStructFromCopy(&PPU, SnapPPU, COUNT(SnapPPU), local_ppu, version);

		struct SDMASnapshot	dma_snap;
		UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version);

		memcpy(Memory.VRAM, local_vram, 0x10000);

		memcpy(Memory.RAM, local_ram, 0x20000);

		memcpy(Memory.SRAM, local_sram, 0x20000);

		memcpy(Memory.FillRAM, local_fillram, 0x8000);

        if(version < SNAPSHOT_VERSION_BAPU) {
            printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION);
            S9xAPULoadBlarggState(local_apu_sound);
        } else
		    S9xAPULoadState(local_apu_sound);

		struct SControlSnapshot	ctl_snap;
		UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version);

		UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version);

		if (local_superfx)
		{
			GSU.avRegAddr = (uint8 *) &GSU.avReg;
			UnfreezeStructFromCopy(&GSU, SnapFX, COUNT(SnapFX), local_superfx, version);
		}

		if (local_sa1)
			UnfreezeStructFromCopy(&SA1, SnapSA1, COUNT(SnapSA1), local_sa1, version);

		if (local_sa1_registers)
			UnfreezeStructFromCopy(&SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers), local_sa1_registers, version);

		if (local_dsp1)
			UnfreezeStructFromCopy(&DSP1, SnapDSP1, COUNT(SnapDSP1), local_dsp1, version);

		if (local_dsp2)
			UnfreezeStructFromCopy(&DSP2, SnapDSP2, COUNT(SnapDSP2), local_dsp2, version);

		if (local_dsp4)
			UnfreezeStructFromCopy(&DSP4, SnapDSP4, COUNT(SnapDSP4), local_dsp4, version);

		if (local_cx4_data)
			memcpy(Memory.C4RAM, local_cx4_data, 8192);

		if (local_st010)
			UnfreezeStructFromCopy(&ST010, SnapST010, COUNT(SnapST010), local_st010, version);

		if (local_obc1)
			UnfreezeStructFromCopy(&OBC1, SnapOBC1, COUNT(SnapOBC1), local_obc1, version);

		if (local_obc1_data)
			memcpy(Memory.OBC1RAM, local_obc1_data, 8192);

		if (local_spc7110)
			UnfreezeStructFromCopy(&s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), local_spc7110, version);

		if (local_srtc)
			UnfreezeStructFromCopy(&srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap), local_srtc, version);

		if (local_rtc_data)
			memcpy(RTCData.reg, local_rtc_data, 20);

		if (local_bsx_data)
			UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version);

		if (local_msu1_data)
			UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version);

		if (version < SNAPSHOT_VERSION_IRQ)
		{
			printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION);

			CPU.NMILine = (CPU.Flags & (1 <<  7)) ? TRUE : FALSE;
			CPU.IRQLine = (CPU.Flags & (1 << 11)) ? TRUE : FALSE;
			CPU.IRQTransition = FALSE;
			CPU.IRQLastState = FALSE;
			CPU.IRQExternal = (Obsolete.CPU_IRQActive & ~(1 << 1)) ? TRUE : FALSE;

			switch (CPU.WhichEvent)
			{
				case 12:	case   1:	CPU.WhichEvent = 1; break;
				case  2:	case   3:	CPU.WhichEvent = 2; break;
				case  4:	case   5:	CPU.WhichEvent = 3; break;
				case  6:	case   7:	CPU.WhichEvent = 4; break;
				case  8:	case   9:	CPU.WhichEvent = 5; break;
				case 10:	case  11:	CPU.WhichEvent = 6; break;
			}

			if (local_sa1) // FIXME
			{
				SA1.Cycles = SA1.PrevCycles = 0;
				SA1.TimerIRQLastState = FALSE;
				SA1.HTimerIRQPos = Memory.FillRAM[0x2212] | (Memory.FillRAM[0x2213] << 8);
				SA1.VTimerIRQPos = Memory.FillRAM[0x2214] | (Memory.FillRAM[0x2215] << 8);
				SA1.HCounter = 0;
				SA1.VCounter = 0;
				SA1.PrevHCounter = 0;
				SA1.MemSpeed = SLOW_ONE_CYCLE;
				SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
			}
		}

		CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
		ICPU.ShiftedPB = Registers.PB << 16;
		ICPU.ShiftedDB = Registers.DB << 16;
		S9xSetPCBase(Registers.PBPC);
		S9xUnpackStatus();
		S9xFixCycles();

		for (int d = 0; d < 8; d++)
			DMA[d] = dma_snap.dma[d];
		CPU.InDMA = CPU.InHDMA = FALSE;
		CPU.InDMAorHDMA = CPU.InWRAMDMAorHDMA = FALSE;
		CPU.HDMARanInDMA = 0;

		S9xFixColourBrightness();
		IPPU.ColorsChanged = TRUE;
		IPPU.OBJChanged = TRUE;
		IPPU.RenderThisFrame = TRUE;

		uint8 hdma_byte = Memory.FillRAM[0x420c];
		S9xSetCPU(hdma_byte, 0x420c);

		S9xControlPostLoadState(&ctl_snap);

		if (local_superfx)
		{
			GSU.pfPlot = fx_PlotTable[GSU.vMode];
			GSU.pfRpix = fx_PlotTable[GSU.vMode + 5];
		}

		if (local_sa1 && local_sa1_registers)
		{
			SA1.Flags |= sa1_old_flags & TRACE_FLAG;
			S9xSA1PostLoadState();
		}

		if (Settings.SDD1)
			S9xSDD1PostLoadState();

		if (local_spc7110)
			S9xSPC7110PostLoadState(version);

		if (local_srtc)
			S9xSRTCPostLoadState(version);

		if (local_bsx_data)
			S9xBSXPostLoadState();

		if (local_msu1_data)
			S9xMSU1PostLoadState();

		if (local_screenshot)
		{
			SnapshotScreenshotInfo	*ssi = new SnapshotScreenshotInfo;

			UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version);

			IPPU.RenderedScreenWidth  = min(ssi->Width,  IMAGE_WIDTH);
			IPPU.RenderedScreenHeight = min(ssi->Height, IMAGE_HEIGHT);
			const bool8 scaleDownX = IPPU.RenderedScreenWidth  < ssi->Width;
			const bool8 scaleDownY = IPPU.RenderedScreenHeight < ssi->Height && ssi->Height > SNES_HEIGHT_EXTENDED;
			GFX.DoInterlace = Settings.SupportHiRes ? ssi->Interlaced : 0;

			uint8	*rowpix = ssi->Data;
			uint16	*screen = GFX.Screen;

			for (int y = 0; y < IPPU.RenderedScreenHeight; y++, screen += GFX.RealPPL)
			{
				for (int x = 0; x < IPPU.RenderedScreenWidth; x++)
				{
					uint32	r, g, b;

					r = *(rowpix++);
					g = *(rowpix++);
					b = *(rowpix++);

					if (scaleDownX)
					{
						r = (r + *(rowpix++)) >> 1;
						g = (g + *(rowpix++)) >> 1;
						b = (b + *(rowpix++)) >> 1;

						if (x + x + 1 >= ssi->Width)
							break;
					}

					screen[x] = BUILD_PIXEL(r, g, b);
				}

				if (scaleDownY)
				{
					rowpix += 3 * ssi->Width;
					if (y + y + 1 >= ssi->Height)
						break;
				}
			}

			// black out what we might have missed
			for (uint32 y = IPPU.RenderedScreenHeight; y < (uint32) (IMAGE_HEIGHT); y++)
				memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);

			delete ssi;
		}
		else
		{
			// couldn't load graphics, so black out the screen instead
			for (uint32 y = 0; y < (uint32) (IMAGE_HEIGHT); y++)
				memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);
		}
	}

	if (local_cpu)				delete [] local_cpu;
	if (local_registers)		delete [] local_registers;
	if (local_ppu)				delete [] local_ppu;
	if (local_dma)				delete [] local_dma;
	if (local_vram)				delete [] local_vram;
	if (local_ram)				delete [] local_ram;
	if (local_sram)				delete [] local_sram;
	if (local_fillram)			delete [] local_fillram;
	if (local_apu_sound)		delete [] local_apu_sound;
	if (local_control_data)		delete [] local_control_data;
	if (local_timing_data)		delete [] local_timing_data;
	if (local_superfx)			delete [] local_superfx;
	if (local_sa1)				delete [] local_sa1;
	if (local_sa1_registers)	delete [] local_sa1_registers;
	if (local_dsp1)				delete [] local_dsp1;
	if (local_dsp2)				delete [] local_dsp2;
	if (local_dsp4)				delete [] local_dsp4;
	if (local_cx4_data)			delete [] local_cx4_data;
	if (local_st010)			delete [] local_st010;
	if (local_obc1)				delete [] local_obc1;
	if (local_obc1_data)		delete [] local_obc1_data;
	if (local_spc7110)			delete [] local_spc7110;
	if (local_srtc)				delete [] local_srtc;
	if (local_rtc_data)			delete [] local_rtc_data;
	if (local_bsx_data)			delete [] local_bsx_data;
	if (local_screenshot)		delete [] local_screenshot;
	if (local_movie_data)		delete [] local_movie_data;

	return (result);
}