Exemple #1
0
static void S9xSoftResetCPU (void)
{
	CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector.
	CPU.PrevCycles = CPU.Cycles;
	CPU.V_Counter = 0;
	CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
	CPU.PCBase = NULL;
	CPU.NMILine = FALSE;
	CPU.IRQLine = FALSE;
	CPU.IRQTransition = FALSE;
	CPU.IRQLastState = FALSE;
	CPU.IRQExternal = FALSE;
	CPU.IRQPending = Timings.IRQPendCount;
	CPU.MemSpeed = SLOW_ONE_CYCLE;
	CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
	CPU.FastROMSpeed = SLOW_ONE_CYCLE;
	CPU.InDMA = FALSE;
	CPU.InHDMA = FALSE;
	CPU.InDMAorHDMA = FALSE;
	CPU.InWRAMDMAorHDMA = FALSE;
	CPU.HDMARanInDMA = 0;
	CPU.CurrentDMAorHDMAChannel = -1;
	CPU.WhichEvent = HC_RENDER_EVENT;
	CPU.NextEvent  = Timings.RenderPos;
	CPU.WaitingForInterrupt = FALSE;
	CPU.AutoSaveTimer = 0;
	CPU.SRAMModified = FALSE;

	Registers.PBPC = 0;
	Registers.PB = 0;
	Registers.PCw = S9xGetWord(0xfffc);
	OpenBus = Registers.PCh;
	Registers.D.W = 0;
	Registers.DB = 0;
	Registers.SH = 1;
	Registers.SL -= 3;
	Registers.XH = 0;
	Registers.YH = 0;

	ICPU.ShiftedPB = 0;
	ICPU.ShiftedDB = 0;
	SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
	ClearFlags(Decimal);

	Timings.InterlaceField = FALSE;
	Timings.H_Max = Timings.H_Max_Master;
	Timings.V_Max = Timings.V_Max_Master;
	Timings.NMITriggerPos = 0xffff;
	if (Model->_5A22 == 2)
		Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2;
	else
		Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;

	S9xSetPCBase(Registers.PBPC);

	ICPU.S9xOpcodes = S9xOpcodesE1;
	ICPU.S9xOpLengths = S9xOpLengthsM1X1;

	S9xUnpackStatus();
}
Exemple #2
0
void S9xResetCPU ()
{		
    CPUPack.Registers.PB = 0;
    CPUPack.Registers.PC = S9xGetWord (0xFFFC);
    CPUPack.Registers.D.W = 0;
    CPUPack.Registers.DB = 0;
    CPUPack.Registers.SH = 1;
    CPUPack.Registers.SL = 0xFF;
    CPUPack.Registers.XH = 0;
    CPUPack.Registers.YH = 0;
    CPUPack.Registers.P.W = 0;

    CPUPack.ICPU.ShiftedPB = 0;
    CPUPack.ICPU.ShiftedDB = 0;
    SetFlags (MemoryFlag | IndexFlag | IRQ | Emulation);
    ClearFlags (Decimal);

    CPUPack.CPU.Flags = CPUPack.CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
    CPUPack.CPU.BranchSkip = FALSE;
    CPUPack.CPU.NMIActive = FALSE;
    CPUPack.CPU.IRQActive = FALSE;
    CPUPack.CPU.WaitingForInterrupt = FALSE;
    CPUPack.CPU.InDMA = FALSE;
    CPUPack.CPU.WhichEvent = HBLANK_START_EVENT;
    S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HBLANK_START_EVENT;
    
    CPUPack.CPU.PC = NULL;
    CPUPack.CPU.PCBase = NULL;
    CPUPack.CPU.PCAtOpcodeStart = NULL;
    CPUPack.CPU.WaitAddress = NULL;
    CPUPack.CPU.WaitCounter = 0;
    CPUPack.CPU.Cycles = 0;
    old_cpu_cycles=0;
    cpu_glob_cycles=0;
    
    CPUPack.CPU.NextEvent = Settings.HBlankStart;
    CPUPack.CPU.V_Counter = 0;
    CPUPack.CPU.MemSpeed = SLOW_ONE_CYCLE;
    CPUPack.CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
    CPUPack.CPU.FastROMSpeed = SLOW_ONE_CYCLE;
    CPUPack.CPU.AutoSaveTimer = 0;
    CPUPack.CPU.SRAMModified = FALSE;
    // CPUPack.CPU.NMITriggerPoint = 4; // Set when ROM image loaded
    CPUPack.CPU.BRKTriggered = FALSE;
    //CPUPack.CPU.TriedInterleavedMode2 = FALSE; // Reset when ROM image loaded
    CPUPack.CPU.NMICycleCount = 0;
    CPUPack.CPU.IRQCycleCount = 0;
    S9xSetPCBase (CPUPack.Registers.PC);

#ifndef VAR_CYCLES
    CPUPack.ICPU.Speed = S9xE1M1X1;
#endif
    CPUPack.ICPU.S9xOpcodes = S9xOpcodesM1X1;
    CPUPack.ICPU.CPUExecuting = TRUE;

    S9xUnpackStatus();
}
Exemple #3
0
void S9xResetCPU()
{
   ICPU.Registers.PB = 0;
   ICPU.Registers.PC = S9xGetWord(0xFFFC);
   ICPU.Registers.D.W = 0;
   ICPU.Registers.DB = 0;
   ICPU.Registers.SH = 1;
   ICPU.Registers.SL = 0xFF;
   ICPU.Registers.XH = 0;
   ICPU.Registers.YH = 0;
   ICPU.Registers.P.W = 0;

   ICPU.ShiftedPB = 0;
   ICPU.ShiftedDB = 0;
   SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
   ClearFlags(Decimal);

   CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
   CPU.BranchSkip = false;
   CPU.NMIActive = false;
   CPU.IRQActive = false;
   CPU.WaitingForInterrupt = false;
   CPU.InDMA = false;
   CPU.WhichEvent = HBLANK_START_EVENT;
   CPU.PC = NULL;
   CPU.PCBase = NULL;
   CPU.PCAtOpcodeStart = NULL;
   CPU.WaitAddress = NULL;
   CPU.WaitCounter = 0;
   CPU.Cycles = 0;
   CPU.NextEvent = Settings.HBlankStart;
   CPU.V_Counter = 0;
   CPU.MemSpeed = SLOW_ONE_CYCLE;
   CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
   CPU.FastROMSpeed = SLOW_ONE_CYCLE;
   CPU.AutoSaveTimer = 0;
   CPU.SRAMModified = false;
   // CPU.NMITriggerPoint = 4; // Set when ROM image loaded
   CPU.BRKTriggered = false;
   //CPU.TriedInterleavedMode2 = false; // Reset when ROM image loaded
   CPU.NMICycleCount = 0;
   CPU.IRQCycleCount = 0;
   S9xSetPCBase(ICPU.Registers.PC);

   ICPU.S9xOpcodes = S9xOpcodesE1;
   ICPU.CPUExecuting = true;

   S9xUnpackStatus();
}
static int ReadOrigSnapshot (STREAM snap)
{
    char buffer [_MAX_PATH];
    char rom_filename [_MAX_PATH];
    int result;
    int i;
    int j;

    int version;
    int len = strlen (ORIG_SNAPSHOT_MAGIC) + 1 + 4 + 1;
    if (READ_STREAM (buffer, len, snap) != len)
	return (WRONG_FORMAT);
    if (strncmp (buffer, ORIG_SNAPSHOT_MAGIC, strlen (ORIG_SNAPSHOT_MAGIC)) != 0)
	return (WRONG_FORMAT);
    if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > ORIG_SNAPSHOT_VERSION)
	return (WRONG_VERSION);

    if ((result = ReadBlock ("NAM:", rom_filename, _MAX_PATH, snap)) != SUCCESS)
	return (result);

    if ((result = ReadBlock ("HiR:", buffer, 0x41, snap)) != SUCCESS)
	return (result);

    if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
	strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0)
    {
	S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
		    "Current loaded ROM image doesn't match that required by freeze-game file.");
    }

    S9xReset ();
    S9xSetSoundMute (TRUE);
    if ((result = ReadBlock ("CPU:", &OrigCPU, sizeof (OrigCPU), snap)) != SUCCESS)
	return (result);
    OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old;
    Memory.FixROMSpeed ();
    if (version == 3)
    {
	OrigCPU.Cycles = OrigCPU.Cycles_old;
	OrigCPU.NextEvent = OrigCPU.NextEvent_old;
	OrigCPU.V_Counter = OrigCPU.V_Counter_old;
	OrigCPU.MemSpeed = OrigCPU.MemSpeed_old;
	OrigCPU.MemSpeedx2 = OrigCPU.MemSpeedx2_old;
	OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old;
    }
    CPU.Flags = OrigCPU.Flags;
    CPU.BranchSkip = OrigCPU.BranchSkip;
    CPU.NMIActive = OrigCPU.NMIActive;
    CPU.IRQActive = OrigCPU.IRQActive;
    CPU.WaitingForInterrupt = OrigCPU.WaitingForInterrupt;
    CPU.WhichEvent = OrigCPU.WhichEvent;
    CPU.Cycles = OrigCPU.Cycles;
    CPU.NextEvent = OrigCPU.NextEvent;
    CPU.V_Counter = OrigCPU.V_Counter;
    CPU.MemSpeed = OrigCPU.MemSpeed;
    CPU.MemSpeedx2 = OrigCPU.MemSpeedx2;
    CPU.FastROMSpeed = OrigCPU.FastROMSpeed;

    if ((result = ReadBlock ("REG:", &OrigRegisters, sizeof (OrigRegisters), snap)) != SUCCESS)
	return (result);

    Registers = *(struct SRegisters *) &OrigRegisters;

    if ((result = ReadBlock ("PPU:", &OrigPPU, sizeof (OrigPPU), snap)) != SUCCESS)
	return (result);

    if (version == 2)
    {
	OrigPPU.OBJNameSelect = OrigPPU.OBJNameSelect_old << 13;
	OrigPPU.OBJNameBase <<= 1;
	OrigPPU.OBJNameSelect <<= 13;
    }
    PPU.BGMode = OrigPPU.BGMode;
    PPU.BG3Priority = OrigPPU.BG3Priority;
    PPU.Brightness = OrigPPU.Brightness;

    PPU.VMA.High = OrigPPU.VMA.High;
    PPU.VMA.Increment = OrigPPU.VMA.Increment;
    PPU.VMA.Address = OrigPPU.VMA.Address;
    PPU.VMA.Mask1 = OrigPPU.VMA.Mask1;
    PPU.VMA.FullGraphicCount = OrigPPU.VMA.FullGraphicCount;
    PPU.VMA.Shift = OrigPPU.VMA.Shift;

    for (i = 0; i < 4; i++)
    {
	PPU.BG[i].SCBase = OrigPPU.BG[i].SCBase;
	PPU.BG[i].VOffset = OrigPPU.BG[i].VOffset;
	PPU.BG[i].HOffset = OrigPPU.BG[i].HOffset;
	PPU.BG[i].BGSize = OrigPPU.BG[i].BGSize;
	PPU.BG[i].NameBase = OrigPPU.BG[i].NameBase;
	PPU.BG[i].SCSize = OrigPPU.BG[i].SCSize;
    }

    PPU.CGFLIP = OrigPPU.CGFLIP;
    for (i = 0; i < 256; i++)
	PPU.CGDATA [i] = OrigPPU.CGDATA [i];
    PPU.FirstSprite = OrigPPU.FirstSprite;
    for (i = 0; i < 128; i++)
    {
	PPU.OBJ[i].HPos = OrigPPU.OBJ [i].HPos;
	PPU.OBJ[i].VPos = OrigPPU.OBJ [i].VPos;
	PPU.OBJ[i].Name = OrigPPU.OBJ [i].Name;
	PPU.OBJ[i].VFlip = OrigPPU.OBJ [i].VFlip;
	PPU.OBJ[i].HFlip = OrigPPU.OBJ [i].HFlip;
	PPU.OBJ[i].Priority = OrigPPU.OBJ [i].Priority;
	PPU.OBJ[i].Palette = OrigPPU.OBJ [i].Palette;
	PPU.OBJ[i].Size = OrigPPU.OBJ [i].Size;
    }
    PPU.OAMPriorityRotation = OrigPPU.OAMPriorityRotation;
    PPU.OAMAddr = OrigPPU.OAMAddr;

    PPU.OAMFlip = OrigPPU.OAMFlip;
    PPU.OAMTileAddress = OrigPPU.OAMTileAddress;
    PPU.IRQVBeamPos = OrigPPU.IRQVBeamPos;
    PPU.IRQHBeamPos = OrigPPU.IRQHBeamPos;
    PPU.VBeamPosLatched = OrigPPU.VBeamPosLatched;
    PPU.HBeamPosLatched = OrigPPU.HBeamPosLatched;

    PPU.HBeamFlip = OrigPPU.HBeamFlip;
    PPU.VBeamFlip = OrigPPU.VBeamFlip;
    PPU.HVBeamCounterLatched = OrigPPU.HVBeamCounterLatched;

    PPU.MatrixA = OrigPPU.MatrixA;
    PPU.MatrixB = OrigPPU.MatrixB;
    PPU.MatrixC = OrigPPU.MatrixC;
    PPU.MatrixD = OrigPPU.MatrixD;
    PPU.CentreX = OrigPPU.CentreX;
    PPU.CentreY = OrigPPU.CentreY;
    PPU.Joypad1ButtonReadPos = OrigPPU.Joypad1ButtonReadPos;
    PPU.Joypad2ButtonReadPos = OrigPPU.Joypad2ButtonReadPos;
    PPU.Joypad3ButtonReadPos = OrigPPU.Joypad3ButtonReadPos;

    PPU.CGADD = OrigPPU.CGADD;
    PPU.FixedColourRed = OrigPPU.FixedColourRed;
    PPU.FixedColourGreen = OrigPPU.FixedColourGreen;
    PPU.FixedColourBlue = OrigPPU.FixedColourBlue;
    PPU.SavedOAMAddr = OrigPPU.SavedOAMAddr;
    PPU.ScreenHeight = OrigPPU.ScreenHeight;
    PPU.WRAM = OrigPPU.WRAM;
    PPU.ForcedBlanking = OrigPPU.ForcedBlanking;
    PPU.OBJNameSelect = OrigPPU.OBJNameSelect;
    PPU.OBJSizeSelect = OrigPPU.OBJSizeSelect;
    PPU.OBJNameBase = OrigPPU.OBJNameBase;
    PPU.OAMReadFlip = OrigPPU.OAMReadFlip;
    memmove (PPU.OAMData, OrigPPU.OAMData, sizeof (PPU.OAMData));
    PPU.VTimerEnabled = OrigPPU.VTimerEnabled;
    PPU.HTimerEnabled = OrigPPU.HTimerEnabled;
    PPU.HTimerPosition = OrigPPU.HTimerPosition;
    PPU.Mosaic = OrigPPU.Mosaic;
    memmove (PPU.BGMosaic, OrigPPU.BGMosaic, sizeof (PPU.BGMosaic));
    PPU.Mode7HFlip = OrigPPU.Mode7HFlip;
    PPU.Mode7VFlip = OrigPPU.Mode7VFlip;
    PPU.Mode7Repeat = OrigPPU.Mode7Repeat;
    PPU.Window1Left = OrigPPU.Window1Left;
    PPU.Window1Right = OrigPPU.Window1Right;
    PPU.Window2Left = OrigPPU.Window2Left;
    PPU.Window2Right = OrigPPU.Window2Right;
    for (i = 0; i < 6; i++)
    {
	PPU.ClipWindowOverlapLogic [i] = OrigPPU.ClipWindowOverlapLogic [i];
	PPU.ClipWindow1Enable [i] = OrigPPU.ClipWindow1Enable [i];
	PPU.ClipWindow2Enable [i] = OrigPPU.ClipWindow2Enable [i];
	PPU.ClipWindow1Inside [i] = OrigPPU.ClipWindow1Inside [i];
	PPU.ClipWindow2Inside [i] = OrigPPU.ClipWindow2Inside [i];
    }
    PPU.CGFLIPRead = OrigPPU.CGFLIPRead;
    PPU.Need16x8Mulitply = OrigPPU.Need16x8Mulitply;

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

    if ((result = ReadBlock ("DMA:", OrigDMA, sizeof (OrigDMA), snap)) != SUCCESS)
	return (result);

    for (i = 0; i < 8; i++)
    {
	DMA[i].TransferDirection = OrigDMA[i].TransferDirection;
	DMA[i].AAddressFixed = OrigDMA[i].AAddressFixed;
	DMA[i].AAddressDecrement = OrigDMA[i].AAddressDecrement;
	DMA[i].TransferMode = OrigDMA[i].TransferMode;
	DMA[i].ABank = OrigDMA[i].ABank;
	DMA[i].AAddress = OrigDMA[i].AAddress;
	DMA[i].Address = OrigDMA[i].Address;
	DMA[i].BAddress = OrigDMA[i].BAddress;
	DMA[i].TransferBytes = OrigDMA[i].TransferBytes;
	DMA[i].HDMAIndirectAddressing = OrigDMA[i].HDMAIndirectAddressing;
	DMA[i].IndirectAddress = OrigDMA[i].IndirectAddress;
	DMA[i].IndirectBank = OrigDMA[i].IndirectBank;
	DMA[i].Repeat = OrigDMA[i].Repeat;
	DMA[i].LineCount = OrigDMA[i].LineCount;
	DMA[i].FirstLine = OrigDMA[i].FirstLine;
    }

    if ((result = ReadBlock ("VRA:", Memory.VRAM, 0x10000, snap)) != SUCCESS)
	return (result);
    if ((result = ReadBlock ("RAM:", Memory.RAM, 0x20000, snap)) != SUCCESS)
	return (result);
    if ((result = ReadBlock ("SRA:", Memory.SRAM, 0x10000, snap)) != SUCCESS)
	return (result);
    if ((result = ReadBlock ("FIL:", Memory.FillRAM, 0x8000, snap)) != SUCCESS)
	return (result);
    if (ReadBlock ("APU:", &OrigAPU, sizeof (OrigAPU), snap) == SUCCESS)
    {
	APU = *(struct SAPU *) &OrigAPU;

	if ((result = ReadBlock ("ARE:", &OrigAPURegisters,
				 sizeof (OrigAPURegisters), snap)) != SUCCESS)
	    return (result);
	APURegisters = *(struct SAPURegisters *) &OrigAPURegisters;
	if ((result = ReadBlock ("ARA:", IAPU.RAM, 0x10000, snap)) != SUCCESS)
	    return (result);
	if ((result = ReadBlock ("SOU:", &OrigSoundData,
				 sizeof (SOrigSoundData), snap)) != SUCCESS)
	    return (result);

	SoundData.master_volume_left = OrigSoundData.master_volume_left;
	SoundData.master_volume_right = OrigSoundData.master_volume_right;
	SoundData.echo_volume_left = OrigSoundData.echo_volume_left;
	SoundData.echo_volume_right = OrigSoundData.echo_volume_right; 
	SoundData.echo_enable = OrigSoundData.echo_enable;
	SoundData.echo_feedback = OrigSoundData.echo_feedback;
	SoundData.echo_ptr = OrigSoundData.echo_ptr;
	SoundData.echo_buffer_size = OrigSoundData.echo_buffer_size;
	SoundData.echo_write_enabled = OrigSoundData.echo_write_enabled;
	SoundData.echo_channel_enable = OrigSoundData.echo_channel_enable;
	SoundData.pitch_mod = OrigSoundData.pitch_mod;

	for (i = 0; i < 3; i++)
	    SoundData.dummy [i] = OrigSoundData.dummy [i];
	for (i = 0; i < NUM_CHANNELS; i++)
	{
	    SoundData.channels [i].state = OrigSoundData.channels [i].state;
	    SoundData.channels [i].type = OrigSoundData.channels [i].type;
	    SoundData.channels [i].volume_left = OrigSoundData.channels [i].volume_left;
	    SoundData.channels [i].volume_right = OrigSoundData.channels [i].volume_right;
	    SoundData.channels [i].hertz = OrigSoundData.channels [i].frequency;
	    SoundData.channels [i].count = OrigSoundData.channels [i].count;
	    SoundData.channels [i].loop = OrigSoundData.channels [i].loop;
	    SoundData.channels [i].envx = OrigSoundData.channels [i].envx;
	    SoundData.channels [i].left_vol_level = OrigSoundData.channels [i].left_vol_level;
	    SoundData.channels [i].right_vol_level = OrigSoundData.channels [i].right_vol_level;
	    SoundData.channels [i].envx_target = OrigSoundData.channels [i].envx_target;
	    SoundData.channels [i].env_error = OrigSoundData.channels [i].env_error;
	    SoundData.channels [i].erate = OrigSoundData.channels [i].erate;
	    SoundData.channels [i].direction = OrigSoundData.channels [i].direction;
	    SoundData.channels [i].attack_rate = OrigSoundData.channels [i].attack_rate;
	    SoundData.channels [i].decay_rate = OrigSoundData.channels [i].decay_rate;
	    SoundData.channels [i].sustain_rate = OrigSoundData.channels [i].sustain_rate;
	    SoundData.channels [i].release_rate = OrigSoundData.channels [i].release_rate;
	    SoundData.channels [i].sustain_level = OrigSoundData.channels [i].sustain_level;
	    SoundData.channels [i].sample = OrigSoundData.channels [i].sample;
	    for (j = 0; j < 16; j++)
		SoundData.channels [i].decoded [j] = OrigSoundData.channels [i].decoded [j];

	    for (j = 0; j < 2; j++)
		SoundData.channels [i].previous [j] = OrigSoundData.channels [i].previous [j];

	    SoundData.channels [i].sample_number = OrigSoundData.channels [i].sample_number;
	    SoundData.channels [i].last_block = OrigSoundData.channels [i].last_block;
	    SoundData.channels [i].needs_decode = OrigSoundData.channels [i].needs_decode;
	    SoundData.channels [i].block_pointer = OrigSoundData.channels [i].block_pointer;
	    SoundData.channels [i].sample_pointer = OrigSoundData.channels [i].sample_pointer;
	    SoundData.channels [i].mode = OrigSoundData.channels [i].mode;
	}

	S9xSetSoundMute (FALSE);
	IAPU.PC = IAPU.RAM + APURegisters.PC;
	S9xAPUUnpackStatus ();
	if (APUCheckDirectPage ())
	    IAPU.DirectPage = IAPU.RAM + 0x100;
	else
	    IAPU.DirectPage = IAPU.RAM;
	Settings.APUEnabled = TRUE;
	IAPU.APUExecuting = TRUE;
    }
    else
    {
	Settings.APUEnabled = FALSE;
	IAPU.APUExecuting = FALSE;
	S9xSetSoundMute (TRUE);
    }
    S9xFixSoundAfterSnapshotLoad (1);
    ICPU.ShiftedPB = Registers.PB << 16;
    ICPU.ShiftedDB = Registers.DB << 16;
    S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
    S9xUnpackStatus ();
    S9xFixCycles ();
    S9xReschedule ();

    return (SUCCESS);
}
Exemple #5
0
static int Unfreeze()
{
   // notaz: overflowing the damn Symbian stack again
   char buffer [16];
   char rom_filename [512];
   int result;

   int version;

   unsigned int len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1;
   if (statef_read(buffer, len) != (int)len)
      return (WRONG_FORMAT);
   if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0)
      return (WRONG_FORMAT);
   if ((version = atoi(&buffer [strlen(SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
      return (WRONG_VERSION);

   if ((result = UnfreezeBlock("NAM", (uint8*) rom_filename, 512)) != SUCCESS)
      return (result);

   if (strcasecmp(rom_filename, Memory.ROMFilename) != 0 &&
         strcasecmp(S9xBasename(rom_filename), S9xBasename(Memory.ROMFilename)) != 0)
   {
      S9xMessage(S9X_WARNING, S9X_FREEZE_ROM_NAME,
                 "Current loaded ROM image doesn't match that required by freeze-game file.");
   }



   uint32 old_flags = CPU.Flags;
#ifdef USE_SA1
   uint32 sa1_old_flags = SA1.Flags;
#endif
   S9xReset();
   S9xSetSoundMute(TRUE);

   if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
                                COUNT(SnapCPU))) != SUCCESS)
      return (result);


   FixROMSpeed();
   CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
                             SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
   if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT(SnapRegisters))) != SUCCESS)
      return (result);
   if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT(SnapPPU))) != SUCCESS)
      return (result);


   IPPU.ColorsChanged = TRUE;
   IPPU.OBJChanged = TRUE;
   CPU.InDMA = FALSE;
   // Restore colors from PPU
   unsigned int i;
   for (i = 0; i < 256; i++)
   {
      IPPU.Red[i] = PPU.CGDATA[i] & 0x1f;
      IPPU.Green[i] = (PPU.CGDATA[i] >> 5) & 0x1f;
      IPPU.Blue[i] = (PPU.CGDATA[i] >> 10) & 0x1f;
   }

   S9xFixColourBrightness();
   IPPU.RenderThisFrame = FALSE;

   if ((result = UnfreezeStruct("DMA", DMA, SnapDMA,
                                COUNT(SnapDMA))) != SUCCESS)
      return (result);

   if ((result = UnfreezeBlock("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
      return (result);

   if ((result = UnfreezeBlock("RAM", Memory.RAM, 0x20000)) != SUCCESS)
      return (result);

   if ((result = UnfreezeBlock("SRA", SRAM, 0x20000)) != SUCCESS)
      return (result);

   if ((result = UnfreezeBlock("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
      return (result);

   // Restore graphics shadow registers
   GFX.r212c_s = Memory.FillRAM[0x212c];
   GFX.r212d_s = Memory.FillRAM[0x212d];
   GFX.r212e_s = Memory.FillRAM[0x212e];
   GFX.r212f_s = Memory.FillRAM[0x212f];
   GFX.r2130_s = Memory.FillRAM[0x2130];
   GFX.r2131_s = Memory.FillRAM[0x2131];

   if (UnfreezeStruct("APU", &APU, SnapAPU, COUNT(SnapAPU)) == SUCCESS)
   {
      SAPURegisters spcregs;
      if ((result = UnfreezeStruct("ARE", &spcregs, SnapAPURegisters,
                                   COUNT(SnapAPURegisters))) != SUCCESS)
         return (result);
      // reload all SPC700 regs from savestate compatible struct
      IAPU.P = spcregs.P;
      IAPU.YA.W = spcregs.YA.W;
      IAPU.X = spcregs.X;
      IAPU.S = spcregs.S;
      IAPU.PC = IAPU.RAM + spcregs.PC;

      if ((result = UnfreezeBlock("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
         return (result);

      if ((result = UnfreezeStruct("SOU", &SoundData, SnapSoundData,
                                   COUNT(SnapSoundData))) != SUCCESS)
         return (result);

      // notaz: just to be sure
      int u;
      for (u = 0; u < 8; u++)
      {
         SoundData.channels[u].env_ind_attack &= 0xf;
         SoundData.channels[u].env_ind_decay  &= 0x7;
         SoundData.channels[u].env_ind_sustain &= 0x1f;
      }

      S9xSetSoundMute(FALSE);
      S9xAPUUnpackStatus();
      if (APUCheckDirectPage())
         IAPU.DirectPage = IAPU.RAM + 0x100;
      else
         IAPU.DirectPage = IAPU.RAM;
      Settings.APUEnabled = TRUE;
      /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
   }
   else
   {
      Settings.APUEnabled = FALSE;
      /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
      S9xSetSoundMute(TRUE);
   }
#ifdef USE_SA1
   if ((result = UnfreezeStruct("SA1", &SA1, SnapSA1,
                                COUNT(SnapSA1))) == SUCCESS)
   {
      if ((result = UnfreezeStruct("SAR", &SA1Registers,
                                   SnapSA1Registers, COUNT(SnapSA1Registers))) != SUCCESS)
         return (result);

      S9xFixSA1AfterSnapshotLoad();
      SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
   }
#endif
   S9xFixSoundAfterSnapshotLoad();
   ICPU.ShiftedPB = Registers.PB << 16;
   ICPU.ShiftedDB = Registers.DB << 16;
   S9xSetPCBase(ICPU.ShiftedPB + Registers.PC);

#ifndef ASMCPU
   S9xUnpackStatus();  // not needed
   S9xFixCycles();  // also not needed?
#endif
   S9xReschedule();

   S9xSRTCPostLoadState();
   if (Settings.SDD1)  S9xSDD1PostLoadState();

   return (SUCCESS);
}