Skip to content
Permalink
mecm
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
/*
* Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
*
* (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
* Jerremy Koot (jkoot@snes9x.com)
*
* Super FX C emulator code
* (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
* Gary Henderson.
* Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
*
* DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
* C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
* C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
*
* DOS port code contains the works of other authors. See headers in
* individual files.
*
* Snes9x homepage: http://www.snes9x.com
*
* Permission to use, copy, modify and distribute Snes9x in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Snes9x is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Snes9x or software derived from Snes9x.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so everyone can benefit from the modifications
* in future versions.
*
* Super NES and Super Nintendo Entertainment System are trademarks of
* Nintendo Co., Limited and its subsidiary companies.
*/
#ifndef __GP32__
/*#include <string.h>
#include <ctype.h>
#include <stdlib.h>*/
#endif
#if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "snapshot.h"
#include "snaporig.h"
#include "memmap.h"
#include "snes9x.h"
#include "65c816.h"
#include "ppu.h"
#include "cpuexec.h"
#include "display.h"
#include "apu.h"
#include "soundux.h"
#include "sa1.h"
#include "srtc.h"
#include "sdd1.h"
#include "spc7110.h"
extern uint8 SRAM[];
#ifdef ZSNES_FX
START_EXTERN_C
void S9xSuperFXPreSaveState ();
void S9xSuperFXPostSaveState ();
void S9xSuperFXPostLoadState ();
END_EXTERN_C
#endif
bool8 S9xUnfreezeZSNES (const char *filename);
typedef struct {
int offset;
int size;
int type;
} FreezeData;
enum {
INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
};
#define Offset(field,structure) \
((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
#define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
#undef OFFSET
#define OFFSET(f) Offset(f,struct SCPUState *)
static FreezeData SnapCPU [] = {
{OFFSET (Flags), 4, INT_V},
{OFFSET (BranchSkip), 1, INT_V},
{OFFSET (NMIActive), 1, INT_V},
{OFFSET (IRQActive), 1, INT_V},
{OFFSET (WaitingForInterrupt), 1, INT_V},
{OFFSET (WhichEvent), 1, INT_V},
{OFFSET (Cycles), 4, INT_V},
{OFFSET (NextEvent), 4, INT_V},
{OFFSET (V_Counter), 4, INT_V},
{OFFSET (MemSpeed), 4, INT_V},
{OFFSET (MemSpeedx2), 4, INT_V},
{OFFSET (FastROMSpeed), 4, INT_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SRegisters *)
static FreezeData SnapRegisters [] = {
{OFFSET (PB), 1, INT_V},
{OFFSET (DB), 1, INT_V},
{OFFSET (P.W), 2, INT_V},
{OFFSET (A.W), 2, INT_V},
{OFFSET (D.W), 2, INT_V},
{OFFSET (S.W), 2, INT_V},
{OFFSET (X.W), 2, INT_V},
{OFFSET (Y.W), 2, INT_V},
{OFFSET (PC), 2, INT_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SPPU *)
static FreezeData SnapPPU [] = {
{OFFSET (BGMode), 1, INT_V},
{OFFSET (BG3Priority), 1, INT_V},
{OFFSET (Brightness), 1, INT_V},
{OFFSET (VMA.High), 1, INT_V},
{OFFSET (VMA.Increment), 1, INT_V},
{OFFSET (VMA.Address), 2, INT_V},
{OFFSET (VMA.Mask1), 2, INT_V},
{OFFSET (VMA.FullGraphicCount), 2, INT_V},
{OFFSET (VMA.Shift), 2, INT_V},
{OFFSET (BG[0].SCBase), 2, INT_V},
{OFFSET (BG[0].VOffset), 2, INT_V},
{OFFSET (BG[0].HOffset), 2, INT_V},
{OFFSET (BG[0].BGSize), 1, INT_V},
{OFFSET (BG[0].NameBase), 2, INT_V},
{OFFSET (BG[0].SCSize), 2, INT_V},
{OFFSET (BG[1].SCBase), 2, INT_V},
{OFFSET (BG[1].VOffset), 2, INT_V},
{OFFSET (BG[1].HOffset), 2, INT_V},
{OFFSET (BG[1].BGSize), 1, INT_V},
{OFFSET (BG[1].NameBase), 2, INT_V},
{OFFSET (BG[1].SCSize), 2, INT_V},
{OFFSET (BG[2].SCBase), 2, INT_V},
{OFFSET (BG[2].VOffset), 2, INT_V},
{OFFSET (BG[2].HOffset), 2, INT_V},
{OFFSET (BG[2].BGSize), 1, INT_V},
{OFFSET (BG[2].NameBase), 2, INT_V},
{OFFSET (BG[2].SCSize), 2, INT_V},
{OFFSET (BG[3].SCBase), 2, INT_V},
{OFFSET (BG[3].VOffset), 2, INT_V},
{OFFSET (BG[3].HOffset), 2, INT_V},
{OFFSET (BG[3].BGSize), 1, INT_V},
{OFFSET (BG[3].NameBase), 2, INT_V},
{OFFSET (BG[3].SCSize), 2, INT_V},
{OFFSET (CGFLIP), 1, INT_V},
{OFFSET (CGDATA), 256, uint16_ARRAY_V},
{OFFSET (FirstSprite), 1, INT_V},
#define O(N) \
{OFFSET (OBJ[N].HPos), 2, INT_V}, \
{OFFSET (OBJ[N].VPos), 2, INT_V}, \
{OFFSET (OBJ[N].Name), 2, INT_V}, \
{OFFSET (OBJ[N].VFlip), 1, INT_V}, \
{OFFSET (OBJ[N].HFlip), 1, INT_V}, \
{OFFSET (OBJ[N].Priority), 1, INT_V}, \
{OFFSET (OBJ[N].Palette), 1, INT_V}, \
{OFFSET (OBJ[N].Size), 1, INT_V}
O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
#undef O
{OFFSET (OAMPriorityRotation), 1, INT_V},
{OFFSET (OAMAddr), 2, INT_V},
{OFFSET (OAMFlip), 1, INT_V},
{OFFSET (OAMTileAddress), 2, INT_V},
{OFFSET (IRQVBeamPos), 2, INT_V},
{OFFSET (IRQHBeamPos), 2, INT_V},
{OFFSET (VBeamPosLatched), 2, INT_V},
{OFFSET (HBeamPosLatched), 2, INT_V},
{OFFSET (HBeamFlip), 1, INT_V},
{OFFSET (VBeamFlip), 1, INT_V},
{OFFSET (HVBeamCounterLatched), 1, INT_V},
{OFFSET (MatrixA), 2, INT_V},
{OFFSET (MatrixB), 2, INT_V},
{OFFSET (MatrixC), 2, INT_V},
{OFFSET (MatrixD), 2, INT_V},
{OFFSET (CentreX), 2, INT_V},
{OFFSET (CentreY), 2, INT_V},
{OFFSET (Joypad1ButtonReadPos), 1, INT_V},
{OFFSET (Joypad2ButtonReadPos), 1, INT_V},
{OFFSET (Joypad3ButtonReadPos), 1, INT_V},
{OFFSET (CGADD), 1, INT_V},
{OFFSET (FixedColourRed), 1, INT_V},
{OFFSET (FixedColourGreen), 1, INT_V},
{OFFSET (FixedColourBlue), 1, INT_V},
{OFFSET (SavedOAMAddr), 2, INT_V},
{OFFSET (ScreenHeight), 2, INT_V},
{OFFSET (WRAM), 4, INT_V},
{OFFSET (ForcedBlanking), 1, INT_V},
{OFFSET (OBJNameSelect), 2, INT_V},
{OFFSET (OBJSizeSelect), 1, INT_V},
{OFFSET (OBJNameBase), 2, INT_V},
{OFFSET (OAMReadFlip), 1, INT_V},
{OFFSET (VTimerEnabled), 1, INT_V},
{OFFSET (HTimerEnabled), 1, INT_V},
{OFFSET (HTimerPosition), 2, INT_V},
{OFFSET (Mosaic), 1, INT_V},
{OFFSET (Mode7HFlip), 1, INT_V},
{OFFSET (Mode7VFlip), 1, INT_V},
{OFFSET (Mode7Repeat), 1, INT_V},
{OFFSET (Window1Left), 1, INT_V},
{OFFSET (Window1Right), 1, INT_V},
{OFFSET (Window2Left), 1, INT_V},
{OFFSET (Window2Right), 1, INT_V},
#define O(N) \
{OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
{OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
{OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
{OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
{OFFSET (ClipWindow2Inside[N]), 1, INT_V}
O(0), O(1), O(2), O(3), O(4), O(5),
#undef O
{OFFSET (CGFLIPRead), 1, INT_V},
{OFFSET (Need16x8Mulitply), 1, INT_V},
{OFFSET (BGMosaic), 4, uint8_ARRAY_V},
{OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
{OFFSET (Need16x8Mulitply), 1, INT_V},
{OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SDMA *)
static FreezeData SnapDMA [] = {
#define O(N) \
{OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
{OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
{OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
{OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
{OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
{OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
#undef O
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SAPU *)
static FreezeData SnapAPU [] = {
{OFFSET (Cycles), 4, INT_V},
{OFFSET (ShowROM), 1, INT_V},
{OFFSET (Flags), 1, INT_V},
{OFFSET (KeyedChannels), 1, INT_V},
{OFFSET (OutPorts), 4, uint8_ARRAY_V},
{OFFSET (DSP), 0x80, uint8_ARRAY_V},
{OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
{OFFSET (Timer), 3, uint16_ARRAY_V},
{OFFSET (TimerTarget), 3, uint16_ARRAY_V},
{OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
{OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SAPURegisters *)
static FreezeData SnapAPURegisters [] = {
{OFFSET (P), 1, INT_V},
{OFFSET (YA.W), 2, INT_V},
{OFFSET (X), 1, INT_V},
{OFFSET (S), 1, INT_V},
{OFFSET (PC), 2, INT_V},
};
#undef OFFSET
#define OFFSET(f) Offset(f,SSoundData *)
static FreezeData SnapSoundData [] = {
{OFFSET (master_volume_left), 2, INT_V},
{OFFSET (master_volume_right), 2, INT_V},
{OFFSET (echo_volume_left), 2, INT_V},
{OFFSET (echo_volume_right), 2, INT_V},
{OFFSET (echo_enable), 4, INT_V},
{OFFSET (echo_feedback), 4, INT_V},
{OFFSET (echo_ptr), 4, INT_V},
{OFFSET (echo_buffer_size), 4, INT_V},
{OFFSET (echo_write_enabled), 4, INT_V},
{OFFSET (echo_channel_enable), 4, INT_V},
{OFFSET (pitch_mod), 4, INT_V},
{OFFSET (dummy), 3, uint32_ARRAY_V},
#define O(N) \
{OFFSET (channels [N].state), 4, INT_V}, \
{OFFSET (channels [N].type), 4, INT_V}, \
{OFFSET (channels [N].volume_left), 2, INT_V}, \
{OFFSET (channels [N].volume_right), 2, INT_V}, \
{OFFSET (channels [N].hertz), 4, INT_V}, \
{OFFSET (channels [N].count), 4, INT_V}, \
{OFFSET (channels [N].loop), 1, INT_V}, \
{OFFSET (channels [N].envx), 4, INT_V}, \
{OFFSET (channels [N].left_vol_level), 2, INT_V}, \
{OFFSET (channels [N].right_vol_level), 2, INT_V}, \
{OFFSET (channels [N].envx_target), 2, INT_V}, \
{OFFSET (channels [N].env_error), 4, INT_V}, \
{OFFSET (channels [N].erate), 4, INT_V}, \
{OFFSET (channels [N].direction), 4, INT_V}, \
{OFFSET (channels [N].attack_rate), 4, INT_V}, \
{OFFSET (channels [N].decay_rate), 4, INT_V}, \
{OFFSET (channels [N].sustain_rate), 4, INT_V}, \
{OFFSET (channels [N].release_rate), 4, INT_V}, \
{OFFSET (channels [N].sustain_level), 4, INT_V}, \
{OFFSET (channels [N].sample), 2, INT_V}, \
{OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
{OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
{OFFSET (channels [N].sample_number), 2, INT_V}, \
{OFFSET (channels [N].last_block), 1, INT_V}, \
{OFFSET (channels [N].needs_decode), 1, INT_V}, \
{OFFSET (channels [N].block_pointer), 4, INT_V}, \
{OFFSET (channels [N].sample_pointer), 4, INT_V}, \
{OFFSET (channels [N].mode), 4, INT_V}
O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
#undef O
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SSA1Registers *)
static FreezeData SnapSA1Registers [] = {
{OFFSET (PB), 1, INT_V},
{OFFSET (DB), 1, INT_V},
{OFFSET (P.W), 2, INT_V},
{OFFSET (A.W), 2, INT_V},
{OFFSET (D.W), 2, INT_V},
{OFFSET (S.W), 2, INT_V},
{OFFSET (X.W), 2, INT_V},
{OFFSET (Y.W), 2, INT_V},
{OFFSET (PC), 2, INT_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SSA1 *)
static FreezeData SnapSA1 [] = {
{OFFSET (Flags), 4, INT_V},
{OFFSET (NMIActive), 1, INT_V},
{OFFSET (IRQActive), 1, INT_V},
{OFFSET (WaitingForInterrupt), 1, INT_V},
{OFFSET (op1), 2, INT_V},
{OFFSET (op2), 2, INT_V},
{OFFSET (arithmetic_op), 4, INT_V},
{OFFSET (sum), 8, INT_V},
{OFFSET (overflow), 1, INT_V}
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SSPC7110Snapshot *)
static FreezeData SnapSPC7110Snap [] = {
{OFFSET (r4801), 1, INT_V},
{OFFSET (r4802), 1, INT_V},
{OFFSET (r4803), 1, INT_V},
{OFFSET (r4804), 1, INT_V},
{OFFSET (r4805), 1, INT_V},
{OFFSET (r4806), 1, INT_V},
{OFFSET (r4807), 1, INT_V},
{OFFSET (r4808), 1, INT_V},
{OFFSET (r4809), 1, INT_V},
{OFFSET (r480a), 1, INT_V},
{OFFSET (r480b), 1, INT_V},
{OFFSET (r480c), 1, INT_V},
{OFFSET (r4811), 1, INT_V},
{OFFSET (r4812), 1, INT_V},
{OFFSET (r4813), 1, INT_V},
{OFFSET (r4814), 1, INT_V},
{OFFSET (r4815), 1, INT_V},
{OFFSET (r4816), 1, INT_V},
{OFFSET (r4817), 1, INT_V},
{OFFSET (r4818), 1, INT_V},
{OFFSET (r481x), 1, INT_V},
{OFFSET (r4814_latch), 1, INT_V},
{OFFSET (r4815_latch), 1, INT_V},
{OFFSET (r4820), 1, INT_V},
{OFFSET (r4821), 1, INT_V},
{OFFSET (r4822), 1, INT_V},
{OFFSET (r4823), 1, INT_V},
{OFFSET (r4824), 1, INT_V},
{OFFSET (r4825), 1, INT_V},
{OFFSET (r4826), 1, INT_V},
{OFFSET (r4827), 1, INT_V},
{OFFSET (r4828), 1, INT_V},
{OFFSET (r4829), 1, INT_V},
{OFFSET (r482a), 1, INT_V},
{OFFSET (r482b), 1, INT_V},
{OFFSET (r482c), 1, INT_V},
{OFFSET (r482d), 1, INT_V},
{OFFSET (r482e), 1, INT_V},
{OFFSET (r482f), 1, INT_V},
{OFFSET (r4830), 1, INT_V},
{OFFSET (r4831), 1, INT_V},
{OFFSET (r4832), 1, INT_V},
{OFFSET (r4833), 1, INT_V},
{OFFSET (r4834), 1, INT_V},
{OFFSET (dx_offset), 4, INT_V},
{OFFSET (ex_offset), 4, INT_V},
{OFFSET (fx_offset), 4, INT_V},
{OFFSET (r4840), 1, INT_V},
{OFFSET (r4841), 1, INT_V},
{OFFSET (r4842), 1, INT_V},
{OFFSET (rtc_state), 4, INT_V},
{OFFSET (rtc_mode), 4, INT_V},
{OFFSET (rtc_index), 4, INT_V},
{OFFSET (decomp_mode), 4, INT_V},
{OFFSET (decomp_offset), 4, INT_V},
{OFFSET (decomp_buffer), SPC7110_DECOMP_BUFFER_SIZE, uint8_ARRAY_V},
{OFFSET (decomp_buffer_rdoffset), 4, INT_V},
{OFFSET (decomp_buffer_wroffset), 4, INT_V},
{OFFSET (decomp_buffer_length), 4, INT_V},
#define O(N) \
{OFFSET (context[N].index), 1, INT_V}, \
{OFFSET (context[N].invert), 1, INT_V}
O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31)
#undef O
};
#undef OFFSET
#define OFFSET(f) Offset(f,struct SSRTCSnapshot *)
static FreezeData SnapSRTCSnap [] = {
{OFFSET (rtc_mode), 4, INT_V},
{OFFSET (rtc_index), 4, INT_V}
};
#ifdef _BSX_151_
#undef OFFSET
#define OFFSET(f) Offset(f,struct SBSX *)
static FreezeData SnapBSX [] = {
{OFFSET (dirty), 1, INT_V},
{OFFSET (dirty2), 1, INT_V},
{OFFSET (bootup), 1, INT_V},
{OFFSET (flash_enable), 1, INT_V},
{OFFSET (write_enable), 1, INT_V},
{OFFSET (read_enable), 1, INT_V},
{OFFSET (flash_command), 4, INT_V},
{OFFSET (old_write), 4, INT_V},
{OFFSET (new_write), 4, INT_V},
{OFFSET (out_index), 1, INT_V},
{OFFSET (output), 32, uint8_ARRAY_V},
{OFFSET (PPU), 32, uint8_ARRAY_V},
{OFFSET (MMC), 16, uint8_ARRAY_V},
{OFFSET (prevMMC), 16, uint8_ARRAY_V},
{OFFSET (test2192), 32, uint8_ARRAY_V}
};
#endif
static char ROMFilename [_MAX_PATH];
//static char SnapshotFilename [_MAX_PATH];
static void Freeze (STREAM);
static int Unfreeze (STREAM);
void FreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields,
int num_fields);
void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size);
int UnfreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields,
int num_fields);
int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size);
bool8 Snapshot (const char *filename)
{
return (S9xFreezeGame (filename));
}
bool8 S9xFreezeGame (const char *filename)
{
STREAM stream = NULL;
if (S9xOpenSnapshotFile (filename, FALSE, &stream))
{
Freeze (stream);
S9xCloseSnapshotFile (stream);
return (TRUE);
}
return (FALSE);
}
bool8 S9xLoadSnapshot (const char *filename)
{
return (S9xUnfreezeGame (filename));
}
bool8 S9xUnfreezeGame_Internal (const char *filename);
void debug_dump(const char* filename);
bool8 S9xUnfreezeGame (const char *filename)
{
bool8 bRet;
S9xSuspendSoundProcess();
bRet = S9xUnfreezeGame_Internal(filename);
//debug_dump("LoadSnap");
S9xResumeSoundProcess();
return bRet;
}
bool8 S9xUnfreezeGame_Internal (const char *filename)
{
if (S9xUnfreezeZSNES (filename))
return (TRUE);
// if (S9xLoadOrigSnapshot (filename))
// return (TRUE);
STREAM snapshot = NULL;
if (S9xOpenSnapshotFile (filename, TRUE, &snapshot))
{
int result;
if ((result = Unfreeze (snapshot)) != SUCCESS)
{
switch (result)
{
case WRONG_FORMAT:
S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
"File not in Snes9x freeze format");
//S9xReset();
break;
case WRONG_VERSION:
S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
"Incompatable Snes9x freeze file format version");
//S9xReset();
break;
default:
case FILE_NOT_FOUND:
sprintf (String, "ROM image \"%s\" for freeze file not found",
ROMFilename);
S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String);
break;
}
S9xCloseSnapshotFile (snapshot);
return (FALSE);
}
S9xCloseSnapshotFile (snapshot);
return (TRUE);
}
return (FALSE);
}
static void Freeze_Internal (STREAM stream);
static void Freeze (STREAM stream)
{
S9xSuspendSoundProcess();
//debug_dump("SaveSnap");
Freeze_Internal(stream);
S9xResumeSoundProcess();
}
static void Freeze_Internal (STREAM stream)
{
char buffer[1024];
int i;
S9xSetSoundMute (TRUE);
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPreSaveState ();
#endif
//S9xSRTCPreSaveState ();
for (i = 0; i < 8; i++)
{
SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
}
sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
WRITE_STREAM (buffer, strlen (buffer), stream);
sprintf (buffer, "NAM:%06d:%s%c", strlen (ROMFilename) + 1,
ROMFilename, 0);
WRITE_STREAM (buffer, strlen (buffer) + 1, stream);
FreezeStruct (stream, "CPU", &CPU, SnapCPU, COUNT (SnapCPU));
FreezeStruct (stream, "REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
FreezeStruct (stream, "PPU", &PPUPack.PPU, SnapPPU, COUNT (SnapPPU));
FreezeStruct (stream, "DMA", DMA, SnapDMA, COUNT (SnapDMA));
// RAM and VRAM
FreezeBlock (stream, "VRA", VRAM, 0x10000);
FreezeBlock (stream, "RAM", RAM, 0x20000);
FreezeBlock (stream, "SRA", SRAM, 0x20000);
FreezeBlock (stream, "FIL", ROM_GLOBAL, 0x8000);
if (Settings.APUEnabled)
{
// APU
FreezeStruct (stream, "APU", &APUPack.APU, SnapAPU, COUNT (SnapAPU));
FreezeStruct (stream, "ARE", &APURegistersUncached, SnapAPURegisters,
COUNT (SnapAPURegisters));
FreezeBlock (stream, "ARA", (IAPUuncached.RAM), 0x10000);
FreezeStruct (stream, "SOU", &SoundData, SnapSoundData,
COUNT (SnapSoundData));
}
if (Settings.SA1)
{
// SA1Registers.PC = SA1.PC - SA1.PCBase;
S9xSA1PackStatus ();
FreezeStruct (stream, "SA1", &SA1, SnapSA1, COUNT (SnapSA1));
FreezeStruct (stream, "SAR", &SA1Registers, SnapSA1Registers,
COUNT (SnapSA1Registers));
}
if (Settings.SPC7110)
{
S9xSPC7110PreSaveState();
FreezeStruct (stream, "S71", &s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap));
}
if (Settings.SRTC)
{
S9xSRTCPreSaveState();
FreezeStruct (stream, "SRT", &srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap));
}
if (Settings.SRTC || Settings.SPC7110RTC)
FreezeBlock (stream, "CLK", RTCData.reg, 20);
#ifdef _BSX_151_
if (Settings.BS)
{
FreezeStruct (stream, "BSX", &BSX, SnapBSX, COUNT (SnapBSX));
}
#endif
S9xSetSoundMute (FALSE);
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPostSaveState ();
#endif
}
static int Unfreeze (STREAM stream)
{
char buffer [_MAX_PATH + 1];
char rom_fname [_MAX_PATH + 1];
int result;
int tmp;
int version;
int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
if ((tmp=READ_STREAM (buffer, len, stream)) != 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 (stream, "NAM", (uint8 *) rom_fname, _MAX_PATH)) != SUCCESS)
{
return (result);
}
if (strcasecmp (rom_fname, ROMFilename) != 0 &&
strcasecmp (S9xBasename (rom_fname), S9xBasename (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;
uint32 sa1_old_flags = SA1.Flags;
S9xReset ();
S9xSetSoundMute (TRUE);
if ((result = UnfreezeStruct (stream, "CPU", &CPU, SnapCPU, COUNT (SnapCPU))) != SUCCESS)
{
return (result);
}
Memory.FixROMSpeed ();
CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
if ((result = UnfreezeStruct (stream, "REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
{
return (result);
}
if ((result = UnfreezeStruct (stream, "PPU", &PPUPack.PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
{
return (result);
}
IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE;
CPU.InDMA = FALSE;
S9xFixColourBrightness ();
IPPU.RenderThisFrame = FALSE;
if ((result = UnfreezeStruct (stream, "DMA", DMA, SnapDMA,
COUNT (SnapDMA))) != SUCCESS)
{
return (result);
}
if ((result = UnfreezeBlock (stream, "VRA", VRAM, 0x10000)) != SUCCESS)
{
return (result);
}
if ((result = UnfreezeBlock (stream, "RAM", RAM, 0x20000)) != SUCCESS)
{
return (result);
}
if ((result = UnfreezeBlock (stream, "SRA", SRAM, 0x20000)) != SUCCESS)
{
return (result);
}
if ((result = UnfreezeBlock (stream, "FIL", ROM_GLOBAL, 0x8000)) != SUCCESS)
{
return (result);
}
if (UnfreezeStruct (stream, "APU", &APUuncached, SnapAPU, COUNT (SnapAPU)) == SUCCESS) {
if ((result = UnfreezeStruct (stream, "ARE", &APURegistersUncached, SnapAPURegisters,COUNT (SnapAPURegisters))) != SUCCESS) {
return (result);
}
if ((result = UnfreezeBlock (stream, "ARA", (IAPUuncached.RAM), 0x10000)) != SUCCESS) {
return (result);
}
if ((result = UnfreezeStruct (stream, "SOU", &SoundData, SnapSoundData,COUNT (SnapSoundData))) != SUCCESS) {
return (result);
}
S9xSetSoundMute (FALSE);
#ifdef ME_SOUND
apu_init_after_load|=2;
(IAPUuncached.PC) = (IAPUuncached.RAM) + (APURegistersUncached.PC);
S9xAPUUnpackStatus ();
if (APUCheckDirectPage ()) (IAPUuncached.DirectPage) = (IAPUuncached.RAM) + 0x100;
else(IAPUuncached.DirectPage) = (IAPUuncached.RAM);
memcpy((void*)Uncache_APU_OutPorts,APUPack.APU.OutPorts, 4);
#else
apu_init_after_load|=2;
//(IAPUuncached.PC) = (IAPUuncached.RAM) + (APURegistersUncached.PC);
//S9xAPUUnpackStatus ();
//if (APUCheckDirectPage ()) (IAPUuncached.DirectPage) = (IAPUuncached.RAM) + 0x100;
//else(IAPUuncached.DirectPage) = (IAPUuncached.RAM);
#endif
Settings.APUEnabled = TRUE;
(IAPU_APUExecuting) = TRUE;
} else {
Settings.APUEnabled = FALSE;
(IAPU_APUExecuting) = FALSE;
S9xSetSoundMute (TRUE);
}
if (Settings.SA1)
{
if ((result = UnfreezeStruct (stream, "SA1", &SA1, SnapSA1,
COUNT(SnapSA1))) == SUCCESS)
{
if ((result = UnfreezeStruct (stream, "SAR", &SA1Registers,
SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
{
return (result);
}
S9xFixSA1AfterSnapshotLoad ();
SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
}
}
if (Settings.SPC7110)
{
if ((result = UnfreezeStruct (stream, "S71", &s7snap, SnapSPC7110Snap, COUNT (SnapSPC7110Snap))) != SUCCESS)
return (result);
}
if (Settings.SRTC)
{
if ((result = UnfreezeStruct (stream, "SRT", &srtcsnap, SnapSRTCSnap, COUNT (SnapSRTCSnap))) != SUCCESS)
return (result);
}
if (Settings.SRTC || Settings.SPC7110RTC)
{
if ((result = UnfreezeBlock (stream, "CLK", RTCData.reg, 20)) != SUCCESS)
return (result);
}
#ifdef _BSX_151_
// BS
if (Settings.BS)
{
if ((result = UnfreezeStruct (stream, "BSX", &BSX, SnapBSX, COUNT (SnapBSX))) != SUCCESS)
return (result);
}
#endif
#ifdef ME_SOUND
S9xFixSoundAfterSnapshotLoad ();
#else
//S9xFixSoundAfterSnapshotLoad ();
#endif
ICPU.ShiftedPB = Registers.PB << 16;
ICPU.ShiftedDB = Registers.DB << 16;
S9xSetPCBase (ICPU.ShiftedPB + Registers.PCw);
S9xUnpackStatus ();
S9xFixCycles ();
S9xReschedule ();
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPostLoadState ();
#endif
if (Settings.SPC7110)
S9xSPC7110PostLoadState();
if (Settings.SRTC)
S9xSRTCPostLoadState();
//S9xSRTCPostLoadState ();
if (Settings.SDD1) S9xSDD1PostLoadState ();
// (IAPUuncached.NextAPUTimerPos) = CPU.Cycles * 10000L;
// (IAPUuncached.APUTimerCounter) = 0;
// sceKernelDcacheWritebackInvalidateAll();
return (SUCCESS);
}
int FreezeSize (int size, int type)
{
switch (type)
{
case uint16_ARRAY_V:
return (size * 2);
case uint32_ARRAY_V:
return (size * 4);
default:
return (size);
}
}
void FreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields,
int num_fields)
{
// Work out the size of the required block
int len = 0;
int i;
int j;
for (i = 0; i < num_fields; i++)
{
if (fields [i].offset + FreezeSize (fields [i].size,
fields [i].type) > len)
len = fields [i].offset + FreezeSize (fields [i].size,
fields [i].type);
}
// uint8 *block = new uint8 [len];
uint8 *block = (uint8*)malloc(len);
uint8 *ptr = block;
uint16 word;
uint32 dword;
int64 qword;
// Build the block ready to be streamed out
for (i = 0; i < num_fields; i++)
{
switch (fields [i].type)
{
case INT_V:
switch (fields [i].size)
{
case 1:
*ptr++ = *((uint8 *) base + fields [i].offset);
break;
case 2:
word = *((uint16 *) ((uint8 *) base + fields [i].offset));
*ptr++ = (uint8) (word >> 8);
*ptr++ = (uint8) word;
break;
case 4:
dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
*ptr++ = (uint8) (dword >> 24);
*ptr++ = (uint8) (dword >> 16);
*ptr++ = (uint8) (dword >> 8);
*ptr++ = (uint8) dword;
break;
case 8:
qword = *((int64 *) ((uint8 *) base + fields [i].offset));
*ptr++ = (uint8) (qword >> 56);
*ptr++ = (uint8) (qword >> 48);
*ptr++ = (uint8) (qword >> 40);
*ptr++ = (uint8) (qword >> 32);
*ptr++ = (uint8) (qword >> 24);
*ptr++ = (uint8) (qword >> 16);
*ptr++ = (uint8) (qword >> 8);
*ptr++ = (uint8) qword;
break;
}
break;
case uint8_ARRAY_V:
memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
ptr += fields [i].size;
break;
case uint16_ARRAY_V:
for (j = 0; j < fields [i].size; j++)
{
word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
*ptr++ = (uint8) (word >> 8);
*ptr++ = (uint8) word;
}
break;
case uint32_ARRAY_V:
for (j = 0; j < fields [i].size; j++)
{
dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
*ptr++ = (uint8) (dword >> 24);
*ptr++ = (uint8) (dword >> 16);
*ptr++ = (uint8) (dword >> 8);
*ptr++ = (uint8) dword;
}
break;
}
}
FreezeBlock (stream, name, block, len);
// delete block;
free(block);
}
void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size)
{
char *buffer;// [512];
buffer=(char*)malloc(512);
sprintf (buffer, "%s:%06d:", name, size);
WRITE_STREAM (buffer, strlen (buffer), stream);
WRITE_STREAM (block, size, stream);
free(buffer);
}
int UnfreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields,
int num_fields)
{
// Work out the size of the required block
int len = 0;
int i;
int j;
for (i = 0; i < num_fields; i++)
{
if (fields [i].offset + FreezeSize (fields [i].size,
fields [i].type) > len)
len = fields [i].offset + FreezeSize (fields [i].size,
fields [i].type);
}
// uint8 *block = new uint8 [len];
uint8 *block = (uint8*)malloc(len);
uint8 *ptr = block;
uint16 word;
uint32 dword;
int64 qword;
int result;
if ((result = UnfreezeBlock (stream, name, block, len)) != SUCCESS)
{
// delete block;
free(block);
return (result);
}
// Unpack the block of data into a C structure
for (i = 0; i < num_fields; i++)
{
switch (fields [i].type)
{
case INT_V:
switch (fields [i].size)
{
case 1:
*((uint8 *) base + fields [i].offset) = *ptr++;
break;
case 2:
word = *ptr++ << 8;
word |= *ptr++;
*((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
break;
case 4:
dword = *ptr++ << 24;
dword |= *ptr++ << 16;
dword |= *ptr++ << 8;
dword |= *ptr++;
*((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
break;
case 8:
qword = (int64) *ptr++ << 56;
qword |= (int64) *ptr++ << 48;
qword |= (int64) *ptr++ << 40;
qword |= (int64) *ptr++ << 32;
qword |= (int64) *ptr++ << 24;
qword |= (int64) *ptr++ << 16;
qword |= (int64) *ptr++ << 8;
qword |= (int64) *ptr++;
*((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
break;
}
break;
case uint8_ARRAY_V:
memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
ptr += fields [i].size;
break;
case uint16_ARRAY_V:
for (j = 0; j < fields [i].size; j++)
{
word = *ptr++ << 8;
word |= *ptr++;
*((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
}
break;
case uint32_ARRAY_V:
for (j = 0; j < fields [i].size; j++)
{
dword = *ptr++ << 24;
dword |= *ptr++ << 16;
dword |= *ptr++ << 8;
dword |= *ptr++;
*((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
}
break;
}
}
// delete block;
free(block);
return (result);
}
int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size)
{
char buffer [20];
int len = 0;
int rem = 0;
int tmp;
if (READ_STREAM (buffer, 11, stream) != 11 ||
strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
(len = atoi (&buffer [4])) == 0)
{
// S9xMessage(0,0,"Block length is 0");
return (WRONG_FORMAT);
}
if (len > size)
{
rem = len - size;
len = size;
}
if ((tmp=READ_STREAM (block, len, stream)) != len)
{
return (WRONG_FORMAT);
}
if (rem)
{
// char *junk = new char [rem];
char *junk = (char*)malloc(rem);
READ_STREAM (junk, rem, stream);
// delete junk;
free(junk);
}
return (SUCCESS);
}
bool8 S9xSPCDump (const char *filename)
{
static uint8 header [] = {
'S', 'N', 'E', 'S', '-', 'S', 'P', 'C', '7', '0', '0', ' ',
'S', 'o', 'u', 'n', 'd', ' ', 'F', 'i', 'l', 'e', ' ',
'D', 'a', 't', 'a', ' ', 'v', '0', '.', '3', '0', 26, 26, 26
};
static uint8 version = {
0x1e
};
FILE *fs;
S9xSetSoundMute (TRUE);
if (!(fs = fopen (filename, "wb")))
return (FALSE);
// The SPC file format:
// 0000: header: 'SNES-SPC700 Sound File Data v0.30',26,26,26
// 0036: version: $1e
// 0037: SPC700 PC:
// 0039: SPC700 A:
// 0040: SPC700 X:
// 0041: SPC700 Y:
// 0042: SPC700 P:
// 0043: SPC700 S:
// 0044: Reserved: 0, 0, 0, 0
// 0048: Title of game: 32 bytes
// 0000: Song name: 32 bytes
// 0000: Name of dumper: 32 bytes
// 0000: Comments: 32 bytes
// 0000: Date of SPC dump: 4 bytes
// 0000: Fade out time in milliseconds: 4 bytes
// 0000: Fade out length in milliseconds: 2 bytes
// 0000: Default channel enables: 1 bytes
// 0000: Emulator used to dump .SPC files: 1 byte, 1 == ZSNES
// 0000: Reserved: 36 bytes
// 0256: SPC700 RAM: 64K
// ----: DSP Registers: 256 bytes
if (fwrite (header, sizeof (header), 1, fs) != 1 ||
fputc (version, fs) == EOF ||
fseek (fs, 37, SEEK_SET) == EOF ||
fputc ((APURegistersUncached.PC) & 0xff, fs) == EOF ||
fputc ((APURegistersUncached.PC) >> 8, fs) == EOF ||
fputc ((APURegistersUncached.YA).B.A, fs) == EOF ||
fputc ((APURegistersUncached.X), fs) == EOF ||
fputc ((APURegistersUncached.YA).B.Y, fs) == EOF ||
fputc ((APURegistersUncached.P), fs) == EOF ||
fputc ((APURegistersUncached.S), fs) == EOF ||
fseek (fs, 256, SEEK_SET) == EOF ||
fwrite ((IAPUuncached.RAM), 0x10000, 1, fs) != 1 ||
fwrite (APUuncached.DSP, 1, 256, fs) != 1 ||
fwrite ((APUuncached.ExtraRAM), 64, 1, fs) != 1 ||
fclose (fs) < 0)
{
S9xSetSoundMute (FALSE);
return (FALSE);
}
S9xSetSoundMute (FALSE);
return (TRUE);
}
bool8 S9xUnfreezeZSNES (const char *filename)
{
STREAM fs;
uint8 *t;//[4000];
if (!(fs = OPEN_STREAM (filename, "rb")))
return (FALSE);
t=(uint8*)malloc(4096);
if (READ_STREAM (t, 64, fs) == 64 &&
strncmp ((char *) t, "ZSNES Save State File V0.6", 26) == 0)
{
S9xReset ();
S9xSetSoundMute (TRUE);
// 28 Curr cycle
CPU.V_Counter = READ_WORD (&t [29]);
// 33 instrset
Settings.APUEnabled = t [36];
// 34 bcycpl cycles per scanline
// 35 cycphb cyclers per hblank
Registers.A.W = READ_WORD (&t [41]);
Registers.DB = t [43];
Registers.PB = t [44];
Registers.S.W = READ_WORD (&t [45]);
Registers.D.W = READ_WORD (&t [47]);
Registers.X.W = READ_WORD (&t [49]);
Registers.Y.W = READ_WORD (&t [51]);
Registers.P.W = READ_WORD (&t [53]);
Registers.PCw = READ_WORD (&t [55]);
READ_STREAM (t, 8, fs);
READ_STREAM (t, 3019, fs);
S9xSetCPU (t [2], 0x4200);
ROM_GLOBAL [0x4210] = t [3];
PPUPack.PPU.IRQVBeamPos = READ_WORD (&t [4]);
PPUPack.PPU.IRQHBeamPos = READ_WORD (&t [2527]);
PPUPack.PPU.Brightness = t [6];
PPUPack.PPU.ForcedBlanking = t [8] >> 7;
int i;
for (i = 0; i < 544; i++)
S9xSetPPU (t [0464 + i], 0x2104);
PPUPack.PPU.OBJNameBase = READ_WORD (&t [9]);
PPUPack.PPU.OBJNameSelect = READ_WORD (&t [13]) - PPUPack.PPU.OBJNameBase;
switch (t [18])
{
case 4:
if (t [17] == 1)
PPUPack.PPU.OBJSizeSelect = 0;
else
PPUPack.PPU.OBJSizeSelect = 6;
break;
case 16:
if (t [17] == 1)
PPUPack.PPU.OBJSizeSelect = 1;
else
PPUPack.PPU.OBJSizeSelect = 3;
break;
default:
case 64:
if (t [17] == 1)
PPUPack.PPU.OBJSizeSelect = 2;
else
if (t [17] == 4)
PPUPack.PPU.OBJSizeSelect = 4;
else
PPUPack.PPU.OBJSizeSelect = 5;
break;
}
PPUPack.PPU.OAMAddr = READ_WORD (&t [25]);
PPUPack.PPU.SavedOAMAddr = READ_WORD (&t [27]);
PPUPack.PPU.FirstSprite = t [29];
PPUPack.PPU.BGMode = t [30];
PPUPack.PPU.BG3Priority = t [31];
PPUPack.PPU.BG[0].BGSize = (t [32] >> 0) & 1;
PPUPack.PPU.BG[1].BGSize = (t [32] >> 1) & 1;
PPUPack.PPU.BG[2].BGSize = (t [32] >> 2) & 1;
PPUPack.PPU.BG[3].BGSize = (t [32] >> 3) & 1;
PPUPack.PPU.Mosaic = t [33] + 1;
PPUPack.PPU.BGMosaic [0] = (t [34] & 1) != 0;
PPUPack.PPU.BGMosaic [1] = (t [34] & 2) != 0;
PPUPack.PPU.BGMosaic [2] = (t [34] & 4) != 0;
PPUPack.PPU.BGMosaic [3] = (t [34] & 8) != 0;
PPUPack.PPU.BG [0].SCBase = READ_WORD (&t [35]) >> 1;
PPUPack.PPU.BG [1].SCBase = READ_WORD (&t [37]) >> 1;
PPUPack.PPU.BG [2].SCBase = READ_WORD (&t [39]) >> 1;
PPUPack.PPU.BG [3].SCBase = READ_WORD (&t [41]) >> 1;
PPUPack.PPU.BG [0].SCSize = t [67];
PPUPack.PPU.BG [1].SCSize = t [68];
PPUPack.PPU.BG [2].SCSize = t [69];
PPUPack.PPU.BG [3].SCSize = t [70];
PPUPack.PPU.BG[0].NameBase = READ_WORD (&t [71]) >> 1;
PPUPack.PPU.BG[1].NameBase = READ_WORD (&t [73]) >> 1;
PPUPack.PPU.BG[2].NameBase = READ_WORD (&t [75]) >> 1;
PPUPack.PPU.BG[3].NameBase = READ_WORD (&t [77]) >> 1;
PPUPack.PPU.BG[0].HOffset = READ_WORD (&t [79]);
PPUPack.PPU.BG[1].HOffset = READ_WORD (&t [81]);
PPUPack.PPU.BG[2].HOffset = READ_WORD (&t [83]);
PPUPack.PPU.BG[3].HOffset = READ_WORD (&t [85]);
PPUPack.PPU.BG[0].VOffset = READ_WORD (&t [89]);
PPUPack.PPU.BG[1].VOffset = READ_WORD (&t [91]);
PPUPack.PPU.BG[2].VOffset = READ_WORD (&t [93]);
PPUPack.PPU.BG[3].VOffset = READ_WORD (&t [95]);
PPUPack.PPU.VMA.Increment = READ_WORD (&t [97]) >> 1;
PPUPack.PPU.VMA.High = t [99];
#ifndef CORRECT_VRAM_READS
IPPU.FirstVRAMRead = t [100];
#endif
S9xSetPPU (t [2512], 0x2115);
PPUPack.PPU.VMA.Address = READ_DWORD (&t [101]);
for (i = 0; i < 512; i++)
S9xSetPPU (t [1488 + i], 0x2122);
PPUPack.PPU.CGADD = (uint8) READ_WORD (&t [105]);
ROM_GLOBAL [0x212c] = t [108];
ROM_GLOBAL [0x212d] = t [109];
PPUPack.PPU.ScreenHeight = READ_WORD (&t [111]);
ROM_GLOBAL [0x2133] = t [2526];
ROM_GLOBAL [0x4202] = t [113];
ROM_GLOBAL [0x4204] = t [114];
ROM_GLOBAL [0x4205] = t [115];
ROM_GLOBAL [0x4214] = t [116];
ROM_GLOBAL [0x4215] = t [117];
ROM_GLOBAL [0x4216] = t [118];
ROM_GLOBAL [0x4217] = t [119];
PPUPack.PPU.VBeamPosLatched = READ_WORD (&t [122]);
PPUPack.PPU.HBeamPosLatched = READ_WORD (&t [120]);
PPUPack.PPU.Window1Left = t [127];
PPUPack.PPU.Window1Right = t [128];
PPUPack.PPU.Window2Left = t [129];
PPUPack.PPU.Window2Right = t [130];
S9xSetPPU (t [131] | (t [132] << 4), 0x2123);
S9xSetPPU (t [133] | (t [134] << 4), 0x2124);
S9xSetPPU (t [135] | (t [136] << 4), 0x2125);
S9xSetPPU (t [137], 0x212a);
S9xSetPPU (t [138], 0x212b);
S9xSetPPU (t [139], 0x212e);
S9xSetPPU (t [140], 0x212f);
S9xSetPPU (t [141], 0x211a);
PPUPack.PPU.MatrixA = READ_WORD (&t [142]);
PPUPack.PPU.MatrixB = READ_WORD (&t [144]);
PPUPack.PPU.MatrixC = READ_WORD (&t [146]);
PPUPack.PPU.MatrixD = READ_WORD (&t [148]);
PPUPack.PPU.CentreX = READ_WORD (&t [150]);
PPUPack.PPU.CentreY = READ_WORD (&t [152]);
// JoyAPos t[154]
// JoyBPos t[155]
ROM_GLOBAL [0x2134] = t [156]; // Matrix mult
ROM_GLOBAL [0x2135] = t [157]; // Matrix mult
ROM_GLOBAL [0x2136] = t [158]; // Matrix mult
PPUPack.PPU.WRAM = READ_DWORD (&t [161]);
for (i = 0; i < 128; i++)
S9xSetCPU (t [165 + i], 0x4300 + i);
if (t [294])
CPU.IRQActive |= PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE;
S9xSetCPU (t [296], 0x420c);
// hdmadata t[297] + 8 * 19
PPUPack.PPU.FixedColourRed = t [450];
PPUPack.PPU.FixedColourGreen = t [451];
PPUPack.PPU.FixedColourBlue = t [452];
S9xSetPPU (t [454], 0x2130);
S9xSetPPU (t [455], 0x2131);
// vraminctype ...
READ_STREAM (RAM, 128 * 1024, fs);
READ_STREAM (VRAM, 64 * 1024, fs);
if (Settings.APUEnabled)
{
// SNES SPC700 RAM (64K)
READ_STREAM ((IAPUuncached.RAM), 64 * 1024, fs);
// Junk 16 bytes
READ_STREAM (t, 16, fs);
// SNES SPC700 state and internal ZSNES SPC700 emulation state
READ_STREAM (t, 304, fs);
(APURegistersUncached.PC) = READ_DWORD (&t [0]);
(APURegistersUncached.YA).B.A = t [4];
(APURegistersUncached.X) = t [8];
(APURegistersUncached.YA).B.Y = t [12];
(APURegistersUncached.P) = t [16];
(APURegistersUncached.S) = t [24];
(APUuncached.Cycles) = READ_DWORD (&t [32]);
Uncache_APU_Cycles = APUuncached.Cycles;
(APUuncached.ShowROM) = ((IAPUuncached.RAM) [0xf1] & 0x80) != 0;
(APUuncached.OutPorts) [0] = t [36];
(APUuncached.OutPorts) [1] = t [37];
(APUuncached.OutPorts) [2] = t [38];
(APUuncached.OutPorts) [3] = t [39];
(APUuncached.TimerEnabled) [0] = (t [40] & 1) != 0;
(APUuncached.TimerEnabled) [1] = (t [40] & 2) != 0;
(APUuncached.TimerEnabled) [2] = (t [40] & 4) != 0;
S9xSetAPUTimer (0xfa, t [41]);
S9xSetAPUTimer (0xfb, t [42]);
S9xSetAPUTimer (0xfc, t [43]);
(APUuncached.Timer) [0] = t [44];
(APUuncached.Timer) [1] = t [45];
(APUuncached.Timer) [2] = t [46];
memmove ((APUuncached.ExtraRAM), &t [48], 64);
// Internal ZSNES sound DSP state
READ_STREAM (t, 1068, fs);
// SNES sound DSP register values
READ_STREAM (t, 256, fs);
uint8 saved = (IAPUuncached.RAM) [0xf2];
for (i = 0; i < 128; i++)
{
switch (i)
{
case APU_KON:
case APU_KOFF:
break;
case APU_FLG:
t [i] &= ~APU_SOFT_RESET;
default:
(IAPUuncached.RAM) [0xf2] = i;
S9xSetAPUDSP (t [i]);
break;
}
}
(IAPUuncached.RAM) [0xf2] = APU_KON;
S9xSetAPUDSP (t [APU_KON]);
(IAPUuncached.RAM) [0xf2] = saved;
S9xSetSoundMute (FALSE);
//#ifdef ME_SOUND
apu_init_after_load|=2;
//#else
// (IAPUuncached.PC) = (IAPUuncached.RAM) + (APURegistersUncached.PC);
// S9xAPUUnpackStatus ();
// if (APUCheckDirectPage ())
// (IAPUuncached.DirectPage) = (IAPUuncached.RAM) + 0x100;
// else
// (IAPUuncached.DirectPage) = (IAPUuncached.RAM);
//#endif
Settings.APUEnabled = TRUE;
(IAPU_APUExecuting) = TRUE;
}
else
{
Settings.APUEnabled = FALSE;
(IAPU_APUExecuting) = FALSE;
S9xSetSoundMute (TRUE);
}
if (Settings.SuperFX)
{
READ_STREAM (SRAM, 64 * 1024, fs);
SEEK_STREAM (64 * 1024, SEEK_CUR,fs);
READ_STREAM (ROM_GLOBAL + 0x7000, 692, fs);
}
if (Settings.SA1)
{
READ_STREAM (t, 2741, fs);
S9xSetSA1 (t [4], 0x2200); // Control
S9xSetSA1 (t [12], 0x2203); // ResetV low
S9xSetSA1 (t [13], 0x2204); // ResetV hi
S9xSetSA1 (t [14], 0x2205); // NMI low
S9xSetSA1 (t [15], 0x2206); // NMI hi
S9xSetSA1 (t [16], 0x2207); // IRQ low
S9xSetSA1 (t [17], 0x2208); // IRQ hi
S9xSetSA1 (((READ_DWORD (&t [28]) - (4096*1024-0x6000))) >> 13, 0x2224);
S9xSetSA1 (t [36], 0x2201);
S9xSetSA1 (t [41], 0x2209);
SA1Registers.A.W = READ_DWORD (&t [592]);
SA1Registers.X.W = READ_DWORD (&t [596]);
SA1Registers.Y.W = READ_DWORD (&t [600]);
SA1Registers.D.W = READ_DWORD (&t [604]);
SA1Registers.DB = t [608];
SA1Registers.PB = t [612];
SA1Registers.S.W = READ_DWORD (&t [616]);
SA1Registers.PCw = READ_DWORD (&t [636]);
SA1Registers.P.W = t [620] | (t [624] << 8);
memmove (&ROM_GLOBAL [0x3000], t + 692, 2 * 1024);
READ_STREAM (SRAM, 64 * 1024, fs);
SEEK_STREAM (64 * 1024, SEEK_CUR,fs);
S9xFixSA1AfterSnapshotLoad ();
}
/* if(Settings.SPC7110)
{
uint32 temp;
READ_STREAM(&s7r.bank50, 0x10000, fs);
//NEWSYM SPCMultA, dd 0 4820-23
READ_STREAM(&temp, 4, fs);
s7r.reg4820=temp&(0x0FF);
s7r.reg4821=(temp>>8)&(0x0FF);
s7r.reg4822=(temp>>16)&(0x0FF);
s7r.reg4823=(temp>>24)&(0x0FF);
//NEWSYM SPCMultB, dd 0 4824-5
READ_STREAM(&temp, 4,fs);
s7r.reg4824=temp&(0x0FF);
s7r.reg4825=(temp>>8)&(0x0FF);
//NEWSYM SPCDivEnd, dd 0 4826-7
READ_STREAM(&temp, 4,fs);
s7r.reg4826=temp&(0x0FF);
s7r.reg4827=(temp>>8)&(0x0FF);
//NEWSYM SPCMulRes, dd 0 4828-B
READ_STREAM(&temp, 4, fs);
s7r.reg4828=temp&(0x0FF);
s7r.reg4829=(temp>>8)&(0x0FF);
s7r.reg482A=(temp>>16)&(0x0FF);
s7r.reg482B=(temp>>24)&(0x0FF);
//NEWSYM SPCDivRes, dd 0 482C-D
READ_STREAM(&temp, 4,fs);
s7r.reg482C=temp&(0x0FF);
s7r.reg482D=(temp>>8)&(0x0FF);
//NEWSYM SPC7110BankA, dd 020100h 4831-3
READ_STREAM(&temp, 4, fs);
s7r.reg4831=temp&(0x0FF);
s7r.reg4832=(temp>>8)&(0x0FF);
s7r.reg4833=(temp>>16)&(0x0FF);
//NEWSYM SPC7110RTCStat, dd 0 4840,init,command, index
READ_STREAM(&temp, 4, fs);
s7r.reg4840=temp&(0x0FF);
//NEWSYM SPC7110RTC, db 00,00,00,00,00,00,01,00,01,00,00,00,00,00,0Fh,00
READ_STREAM(&temp, 4, fs);
if(Settings.SPC7110RTC)
{
rtc_f9.reg[0]=temp&(0x0FF);
rtc_f9.reg[1]=(temp>>8)&(0x0FF);
rtc_f9.reg[2]=(temp>>16)&(0x0FF);
rtc_f9.reg[3]=(temp>>24)&(0x0FF);
}
READ_STREAM(&temp, 4, fs);
if(Settings.SPC7110RTC)
{
rtc_f9.reg[4]=temp&(0x0FF);
rtc_f9.reg[5]=(temp>>8)&(0x0FF);
rtc_f9.reg[6]=(temp>>16)&(0x0FF);
rtc_f9.reg[7]=(temp>>24)&(0x0FF);
}
READ_STREAM(&temp, 4, fs);
if(Settings.SPC7110RTC)
{
rtc_f9.reg[8]=temp&(0x0FF);
rtc_f9.reg[9]=(temp>>8)&(0x0FF);
rtc_f9.reg[10]=(temp>>16)&(0x0FF);
rtc_f9.reg[11]=(temp>>24)&(0x0FF);
}
READ_STREAM(&temp, 4, fs);
if(Settings.SPC7110RTC)
{
rtc_f9.reg[12]=temp&(0x0FF);
rtc_f9.reg[13]=(temp>>8)&(0x0FF);
rtc_f9.reg[14]=(temp>>16)&(0x0FF);
rtc_f9.reg[15]=(temp>>24)&(0x0FF);
}
//NEWSYM SPC7110RTCB, db 00,00,00,00,00,00,01,00,01,00,00,00,00,01,0Fh,06
READ_STREAM(&temp, 4, fs);
READ_STREAM(&temp, 4, fs);
READ_STREAM(&temp, 4, fs);
READ_STREAM(&temp, 4, fs);
//NEWSYM SPCROMPtr, dd 0 4811-4813
READ_STREAM(&temp, 4, fs);
s7r.reg4811=temp&(0x0FF);
s7r.reg4812=(temp>>8)&(0x0FF);
s7r.reg4813=(temp>>16)&(0x0FF);
//NEWSYM SPCROMtoI, dd SPCROMPtr
READ_STREAM(&temp, 4, fs);
//NEWSYM SPCROMAdj, dd 0 4814-5
READ_STREAM(&temp, 4, fs);
s7r.reg4814=temp&(0x0FF);
s7r.reg4815=(temp>>8)&(0x0FF);
//NEWSYM SPCROMInc, dd 0 4816-7
READ_STREAM(&temp, 4, fs);
s7r.reg4816=temp&(0x0FF);
s7r.reg4817=(temp>>8)&(0x0FF);
//NEWSYM SPCROMCom, dd 0 4818
READ_STREAM(&temp, 4, fs);
s7r.reg4818=temp&(0x0FF);
//NEWSYM SPCCompPtr, dd 0 4801-4804 (+b50i) if"manual"
READ_STREAM(&temp, 4, fs);
//do table check
s7r.reg4801=temp&(0x0FF);
s7r.reg4802=(temp>>8)&(0x0FF);
s7r.reg4803=(temp>>16)&(0x0FF);
s7r.reg4804=(temp>>24)&(0x0FF);
///NEWSYM SPCDecmPtr, dd 0 4805-6 +b50i
READ_STREAM(&temp, 4, fs);
s7r.reg4805=temp&(0x0FF);
s7r.reg4806=(temp>>8)&(0x0FF);
//NEWSYM SPCCompCounter, dd 0 4809-A
READ_STREAM(&temp, 4, fs);
s7r.reg4809=temp&(0x0FF);
s7r.reg480A=(temp>>8)&(0x0FF);
//NEWSYM SPCCompCommand, dd 0 480B
READ_STREAM(&temp, 4, fs);
s7r.reg480B=temp&(0x0FF);
//NEWSYM SPCCheckFix, dd 0 written(if 1, then set writtne to max value!)
READ_STREAM(&temp, 4, fs);
(temp&(0x0FF))?s7r.written=0x1F:s7r.written=0x00;
//NEWSYM SPCSignedVal, dd 0 482E
READ_STREAM(&temp, 4, fs);
s7r.reg482E=temp&(0x0FF);
}*/
CLOSE_STREAM (fs);
Memory.FixROMSpeed ();
IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE;
CPU.InDMA = FALSE;
S9xFixColourBrightness ();
IPPU.RenderThisFrame = FALSE;
S9xFixSoundAfterSnapshotLoad ();
ICPU.ShiftedPB = Registers.PB << 16;
ICPU.ShiftedDB = Registers.DB << 16;
S9xSetPCBase (ICPU.ShiftedPB + Registers.PCw);
S9xUnpackStatus ();
S9xFixCycles ();
S9xReschedule ();
#ifdef ZSNES_FX
if (Settings.SuperFX)
S9xSuperFXPostLoadState ();
#endif
free(t);
return (TRUE);
}
CLOSE_STREAM (fs);
free(t);
return (FALSE);
}