2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
12 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
21 * Permission to use, copy, modify and distribute Snes9x in both binary and
22 * source form, for non-commercial purposes, is hereby granted without fee,
23 * providing that this license information and copyright notice appear with
24 * all copies and any derived work.
26 * This software is provided 'as-is', without any express or implied
27 * warranty. In no event shall the authors be held liable for any damages
28 * arising from the use of this software.
30 * Snes9x is freeware for PERSONAL USE only. Commercial users should
31 * seek permission of the copyright holders first. Commercial use includes
32 * charging money for Snes9x or software derived from Snes9x.
34 * The copyright holders request that bug fixes and improvements to the code
35 * should be forwarded to them so everyone can benefit from the modifications
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
46 #if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)
48 #include <sys/types.h>
71 void S9xSuperFXPreSaveState ();
72 void S9xSuperFXPostSaveState ();
73 void S9xSuperFXPostLoadState ();
74 //bool8 S9xUnfreezeZSNES (const char *filename);
85 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
88 #define Offset(field,structure) \
89 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
91 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
94 #define OFFSET(f) Offset(f,struct SCPUState *)
96 static FreezeData SnapCPU [] = {
97 {OFFSET (Flags), 4, INT_V},
98 {OFFSET (BranchSkip), 1, INT_V},
99 {OFFSET (NMIActive), 1, INT_V},
100 {OFFSET (IRQActive), 1, INT_V},
101 {OFFSET (WaitingForInterrupt), 1, INT_V},
102 {OFFSET (WhichEvent), 1, INT_V},
103 {OFFSET (Cycles), 4, INT_V},
104 {OFFSET (NextEvent), 4, INT_V},
105 {OFFSET (V_Counter), 4, INT_V},
106 {OFFSET (MemSpeed), 4, INT_V},
107 {OFFSET (MemSpeedx2), 4, INT_V},
108 {OFFSET (FastROMSpeed), 4, INT_V}
112 #define OFFSET(f) Offset(f,struct SRegisters *)
114 static FreezeData SnapRegisters [] = {
115 {OFFSET (PB), 1, INT_V},
116 {OFFSET (DB), 1, INT_V},
117 {OFFSET (P.W), 2, INT_V},
118 {OFFSET (A.W), 2, INT_V},
119 {OFFSET (D.W), 2, INT_V},
120 {OFFSET (S.W), 2, INT_V},
121 {OFFSET (X.W), 2, INT_V},
122 {OFFSET (Y.W), 2, INT_V},
123 {OFFSET (PC), 2, INT_V}
127 #define OFFSET(f) Offset(f,struct SPPU *)
129 static FreezeData SnapPPU [] = {
130 {OFFSET (BGMode), 1, INT_V},
131 {OFFSET (BG3Priority), 1, INT_V},
132 {OFFSET (Brightness), 1, INT_V},
133 {OFFSET (VMA.High), 1, INT_V},
134 {OFFSET (VMA.Increment), 1, INT_V},
135 {OFFSET (VMA.Address), 2, INT_V},
136 {OFFSET (VMA.Mask1), 2, INT_V},
137 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
138 {OFFSET (VMA.Shift), 2, INT_V},
139 {OFFSET (BG[0].SCBase), 2, INT_V},
140 {OFFSET (BG[0].VOffset), 2, INT_V},
141 {OFFSET (BG[0].HOffset), 2, INT_V},
142 {OFFSET (BG[0].BGSize), 1, INT_V},
143 {OFFSET (BG[0].NameBase), 2, INT_V},
144 {OFFSET (BG[0].SCSize), 2, INT_V},
146 {OFFSET (BG[1].SCBase), 2, INT_V},
147 {OFFSET (BG[1].VOffset), 2, INT_V},
148 {OFFSET (BG[1].HOffset), 2, INT_V},
149 {OFFSET (BG[1].BGSize), 1, INT_V},
150 {OFFSET (BG[1].NameBase), 2, INT_V},
151 {OFFSET (BG[1].SCSize), 2, INT_V},
153 {OFFSET (BG[2].SCBase), 2, INT_V},
154 {OFFSET (BG[2].VOffset), 2, INT_V},
155 {OFFSET (BG[2].HOffset), 2, INT_V},
156 {OFFSET (BG[2].BGSize), 1, INT_V},
157 {OFFSET (BG[2].NameBase), 2, INT_V},
158 {OFFSET (BG[2].SCSize), 2, INT_V},
160 {OFFSET (BG[3].SCBase), 2, INT_V},
161 {OFFSET (BG[3].VOffset), 2, INT_V},
162 {OFFSET (BG[3].HOffset), 2, INT_V},
163 {OFFSET (BG[3].BGSize), 1, INT_V},
164 {OFFSET (BG[3].NameBase), 2, INT_V},
165 {OFFSET (BG[3].SCSize), 2, INT_V},
167 {OFFSET (CGFLIP), 1, INT_V},
168 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
169 {OFFSET (FirstSprite), 1, INT_V},
171 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
172 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
173 {OFFSET (OBJ[N].Name), 2, INT_V}, \
174 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
175 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
176 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
177 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
178 {OFFSET (OBJ[N].Size), 1, INT_V}
180 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
181 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
182 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
183 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
184 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
185 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
186 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
187 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
188 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
189 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
190 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
191 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
192 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
193 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
194 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
195 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
197 {OFFSET (OAMPriorityRotation), 1, INT_V},
198 {OFFSET (OAMAddr), 2, INT_V},
199 {OFFSET (OAMFlip), 1, INT_V},
200 {OFFSET (OAMTileAddress), 2, INT_V},
201 {OFFSET (IRQVBeamPos), 2, INT_V},
202 {OFFSET (IRQHBeamPos), 2, INT_V},
203 {OFFSET (VBeamPosLatched), 2, INT_V},
204 {OFFSET (HBeamPosLatched), 2, INT_V},
205 {OFFSET (HBeamFlip), 1, INT_V},
206 {OFFSET (VBeamFlip), 1, INT_V},
207 {OFFSET (HVBeamCounterLatched), 1, INT_V},
208 {OFFSET (MatrixA), 2, INT_V},
209 {OFFSET (MatrixB), 2, INT_V},
210 {OFFSET (MatrixC), 2, INT_V},
211 {OFFSET (MatrixD), 2, INT_V},
212 {OFFSET (CentreX), 2, INT_V},
213 {OFFSET (CentreY), 2, INT_V},
214 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
215 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
216 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
217 {OFFSET (CGADD), 1, INT_V},
218 {OFFSET (FixedColourRed), 1, INT_V},
219 {OFFSET (FixedColourGreen), 1, INT_V},
220 {OFFSET (FixedColourBlue), 1, INT_V},
221 {OFFSET (SavedOAMAddr), 2, INT_V},
222 {OFFSET (ScreenHeight), 2, INT_V},
223 {OFFSET (WRAM), 4, INT_V},
224 {OFFSET (ForcedBlanking), 1, INT_V},
225 {OFFSET (OBJNameSelect), 2, INT_V},
226 {OFFSET (OBJSizeSelect), 1, INT_V},
227 {OFFSET (OBJNameBase), 2, INT_V},
228 {OFFSET (OAMReadFlip), 1, INT_V},
229 {OFFSET (VTimerEnabled), 1, INT_V},
230 {OFFSET (HTimerEnabled), 1, INT_V},
231 {OFFSET (HTimerPosition), 2, INT_V},
232 {OFFSET (Mosaic), 1, INT_V},
233 {OFFSET (Mode7HFlip), 1, INT_V},
234 {OFFSET (Mode7VFlip), 1, INT_V},
235 {OFFSET (Mode7Repeat), 1, INT_V},
236 {OFFSET (Window1Left), 1, INT_V},
237 {OFFSET (Window1Right), 1, INT_V},
238 {OFFSET (Window2Left), 1, INT_V},
239 {OFFSET (Window2Right), 1, INT_V},
241 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
242 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
243 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
244 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
245 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
247 O(0), O(1), O(2), O(3), O(4), O(5),
251 {OFFSET (CGFLIPRead), 1, INT_V},
252 {OFFSET (Need16x8Mulitply), 1, INT_V},
253 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
254 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
255 {OFFSET (Need16x8Mulitply), 1, INT_V},
256 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
260 #define OFFSET(f) Offset(f,struct SDMA *)
262 static FreezeData SnapDMA [] = {
264 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
265 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
266 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
267 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
268 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
269 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
270 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
271 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
272 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
273 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
274 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
275 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
276 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
277 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
278 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
280 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
285 #define OFFSET(f) Offset(f,struct SAPU *)
287 static FreezeData SnapAPU [] = {
288 {OFFSET (Cycles), 4, INT_V},
289 {OFFSET (ShowROM), 1, INT_V},
290 {OFFSET (Flags), 1, INT_V},
291 {OFFSET (KeyedChannels), 1, INT_V},
292 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
293 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
294 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
295 {OFFSET (Timer), 3, uint16_ARRAY_V},
296 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
297 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
298 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
302 #define OFFSET(f) Offset(f,struct SAPURegisters *)
304 static FreezeData SnapAPURegisters [] = {
305 {OFFSET (P) , 1, INT_V},
306 {OFFSET (YA.W), 2, INT_V},
307 {OFFSET (X) , 1, INT_V},
308 {OFFSET (S) , 1, INT_V},
309 {OFFSET (PC) , 2, INT_V}
314 #define OFFSET(f) Offset(f,SSoundData *)
316 static FreezeData SnapSoundData [] = {
317 {OFFSET (master_volume_left), 2, INT_V},
318 {OFFSET (master_volume_right), 2, INT_V},
319 {OFFSET (echo_volume_left), 2, INT_V},
320 {OFFSET (echo_volume_right), 2, INT_V},
321 {OFFSET (echo_enable), 4, INT_V},
322 {OFFSET (echo_feedback), 4, INT_V},
323 {OFFSET (echo_ptr), 4, INT_V},
324 {OFFSET (echo_buffer_size), 4, INT_V},
325 {OFFSET (echo_write_enabled), 4, INT_V},
326 {OFFSET (echo_channel_enable), 4, INT_V},
327 {OFFSET (pitch_mod), 4, INT_V},
328 {OFFSET (dummy), 3, uint32_ARRAY_V},
330 {OFFSET (channels [N].state), 4, INT_V}, \
331 {OFFSET (channels [N].type), 4, INT_V}, \
332 {OFFSET (channels [N].volume_left), 2, INT_V}, \
333 {OFFSET (channels [N].volume_right), 2, INT_V}, \
334 {OFFSET (channels [N].hertz), 4, INT_V}, \
335 {OFFSET (channels [N].count), 4, INT_V}, \
336 {OFFSET (channels [N].loop), 1, INT_V}, \
337 {OFFSET (channels [N].envx), 4, INT_V}, \
338 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
339 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
340 {OFFSET (channels [N].envx_target), 2, INT_V}, \
341 {OFFSET (channels [N].env_error), 4, INT_V}, \
342 {OFFSET (channels [N].erate), 4, INT_V}, \
343 {OFFSET (channels [N].direction), 4, INT_V}, \
344 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
345 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
346 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
347 {OFFSET (channels [N].release_rate), 4, INT_V}, \
348 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
349 {OFFSET (channels [N].sample), 2, INT_V}, \
350 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
351 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
352 {OFFSET (channels [N].sample_number), 2, INT_V}, \
353 {OFFSET (channels [N].last_block), 1, INT_V}, \
354 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
355 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
356 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
357 {OFFSET (channels [N].mode), 4, INT_V}
359 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
366 #define OFFSET(f) Offset(f,struct SSA1Registers *)
368 static FreezeData SnapSA1Registers [] = {
369 {OFFSET (PB), 1, INT_V},
370 {OFFSET (DB), 1, INT_V},
371 {OFFSET (P.W), 2, INT_V},
372 {OFFSET (A.W), 2, INT_V},
373 {OFFSET (D.W), 2, INT_V},
374 {OFFSET (S.W), 2, INT_V},
375 {OFFSET (X.W), 2, INT_V},
376 {OFFSET (Y.W), 2, INT_V},
377 {OFFSET (PC), 2, INT_V}
381 #define OFFSET(f) Offset(f,struct SSA1 *)
383 static FreezeData SnapSA1 [] = {
384 {OFFSET (Flags), 4, INT_V},
385 {OFFSET (NMIActive), 1, INT_V},
386 {OFFSET (IRQActive), 1, INT_V},
387 {OFFSET (WaitingForInterrupt), 1, INT_V},
388 {OFFSET (op1), 2, INT_V},
389 {OFFSET (op2), 2, INT_V},
390 {OFFSET (arithmetic_op), 4, INT_V},
391 {OFFSET (sum), 8, INT_V},
392 {OFFSET (overflow), 1, INT_V}
398 static void Freeze ();
399 static int Unfreeze ();
400 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
402 static void FreezeBlock (const char *name, uint8 *block, int size);
404 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
406 static int UnfreezeBlock (const char *name, uint8 *block, int size);
408 bool8 S9xFreezeGame (const char *filename)
410 if ((ss_st = OPEN_STREAM(filename, "wb")))
420 bool8 S9xUnfreezeGame (const char *filename)
422 if ((ss_st = OPEN_STREAM(filename, "rb")))
425 if ((result = Unfreeze()) != SUCCESS)
430 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
431 "File not in Snes9x freeze format");
435 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
436 "Incompatable Snes9x freeze file format version");
440 // should never happen
454 static void Freeze ()
459 S9xSetSoundMute (TRUE);
461 if (Settings.SuperFX)
462 S9xSuperFXPreSaveState ();
465 S9xSRTCPreSaveState ();
467 for (i = 0; i < 8; i++)
469 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
470 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
472 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
473 WRITE_STREAM(buffer, strlen(buffer), ss_st);
474 sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
475 Memory.ROMFilename, 0);
476 WRITE_STREAM(buffer, strlen(buffer) + 1, ss_st);
477 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
478 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
479 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
480 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
483 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
484 FreezeBlock ("RAM", Memory.RAM, 0x20000);
485 FreezeBlock ("SRA", ::SRAM, 0x20000);
486 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
487 if (Settings.APUEnabled)
490 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
491 // copy all SPC700 regs to savestate compatible struct
492 SAPURegisters spcregs;
494 spcregs.YA.W = IAPU.YA.W;
497 spcregs.PC = IAPU.PC - IAPU.RAM;
498 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
499 COUNT (SnapAPURegisters));
501 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
502 FreezeStruct ("SOU", &SoundData, SnapSoundData,
503 COUNT (SnapSoundData));
508 SA1Registers.PC = SA1.PC - SA1.PCBase;
510 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
511 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
512 COUNT (SnapSA1Registers));
515 S9xSetSoundMute (FALSE);
517 if (Settings.SuperFX)
518 S9xSuperFXPostSaveState ();
522 static int Unfreeze()
525 char rom_filename[1024];
529 int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
530 if (READ_STREAM(buffer, len, ss_st) != len)
532 printf("%s: Failed to read header\n", __func__);
535 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
537 printf("%s: Read header not correct\n", __func__);
540 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
542 printf("%s: Wrong version\n", __func__);
543 return WRONG_VERSION;
546 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
548 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
552 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
553 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
555 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
556 "Current loaded ROM image doesn't match that required by freeze-game file.");
560 uint32 old_flags = CPU.Flags;
562 uint32 sa1_old_flags = SA1.Flags;
565 S9xSetSoundMute (TRUE);
567 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
568 COUNT (SnapCPU))) != SUCCESS)
572 Memory.FixROMSpeed ();
573 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
574 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
575 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
577 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
581 IPPU.ColorsChanged = TRUE;
582 IPPU.OBJChanged = TRUE;
584 S9xFixColourBrightness ();
585 IPPU.RenderThisFrame = FALSE;
587 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
588 COUNT (SnapDMA))) != SUCCESS)
591 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
594 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
597 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
600 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
604 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
606 SAPURegisters spcregs;
607 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
608 COUNT (SnapAPURegisters))) != SUCCESS)
610 // reload all SPC700 regs from savestate compatible struct
612 IAPU.YA.W = spcregs.YA.W;
615 IAPU.PC = IAPU.RAM + spcregs.PC;
617 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
620 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
621 COUNT (SnapSoundData))) != SUCCESS)
624 // notaz: just to be sure
625 for(int u=0; u<8; u++) {
626 SoundData.channels[u].env_ind_attack &= 0xf;
627 SoundData.channels[u].env_ind_decay &= 0x7;
628 SoundData.channels[u].env_ind_sustain&= 0x1f;
631 S9xSetSoundMute (FALSE);
632 S9xAPUUnpackStatus ();
633 if (APUCheckDirectPage ())
634 IAPU.DirectPage = IAPU.RAM + 0x100;
636 IAPU.DirectPage = IAPU.RAM;
637 Settings.APUEnabled = TRUE;
638 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
642 Settings.APUEnabled = FALSE;
643 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
644 S9xSetSoundMute (TRUE);
647 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
648 COUNT(SnapSA1))) == SUCCESS)
650 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
651 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
654 S9xFixSA1AfterSnapshotLoad ();
655 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
658 S9xFixSoundAfterSnapshotLoad ();
659 ICPU.ShiftedPB = Registers.PB << 16;
660 ICPU.ShiftedDB = Registers.DB << 16;
661 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
664 //S9xUnpackStatus (); // not needed
665 //S9xFixCycles (); // also not needed?
668 if (Settings.SuperFX)
669 S9xSuperFXPostLoadState ();
672 S9xSRTCPostLoadState ();
673 if (Settings.SDD1) S9xSDD1PostLoadState ();
678 int FreezeSize (int size, int type)
691 void FreezeStruct(const char *name, void *base, FreezeData *fields,
694 // Work out the size of the required block
699 for (i = 0; i < num_fields; i++)
701 if (fields [i].offset + FreezeSize (fields [i].size,
702 fields [i].type) > len)
703 len = fields [i].offset + FreezeSize (fields [i].size,
707 // uint8 *block = new uint8 [len];
708 uint8 *block = (uint8*)malloc(len);
714 // Build the block ready to be streamed out
715 for (i = 0; i < num_fields; i++)
717 switch (fields [i].type)
720 switch (fields [i].size)
723 *ptr++ = *((uint8 *) base + fields [i].offset);
726 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
727 *ptr++ = (uint8) (word >> 8);
728 *ptr++ = (uint8) word;
731 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
732 *ptr++ = (uint8) (dword >> 24);
733 *ptr++ = (uint8) (dword >> 16);
734 *ptr++ = (uint8) (dword >> 8);
735 *ptr++ = (uint8) dword;
738 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
739 *ptr++ = (uint8) (qword >> 56);
740 *ptr++ = (uint8) (qword >> 48);
741 *ptr++ = (uint8) (qword >> 40);
742 *ptr++ = (uint8) (qword >> 32);
743 *ptr++ = (uint8) (qword >> 24);
744 *ptr++ = (uint8) (qword >> 16);
745 *ptr++ = (uint8) (qword >> 8);
746 *ptr++ = (uint8) qword;
751 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
752 ptr += fields [i].size;
755 for (j = 0; j < fields [i].size; j++)
757 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
758 *ptr++ = (uint8) (word >> 8);
759 *ptr++ = (uint8) word;
763 for (j = 0; j < fields [i].size; j++)
765 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
766 *ptr++ = (uint8) (dword >> 24);
767 *ptr++ = (uint8) (dword >> 16);
768 *ptr++ = (uint8) (dword >> 8);
769 *ptr++ = (uint8) dword;
775 FreezeBlock (name, block, len);
780 void FreezeBlock (const char *name, uint8 *block, int size)
783 sprintf (buffer, "%s:%06d:", name, size);
784 WRITE_STREAM(buffer, strlen(buffer), ss_st);
785 WRITE_STREAM(block, size, ss_st);
788 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
791 // Work out the size of the required block
796 for (i = 0; i < num_fields; i++)
798 if (fields [i].offset + FreezeSize (fields [i].size,
799 fields [i].type) > len)
800 len = fields [i].offset + FreezeSize (fields [i].size,
804 uint8 *block = (uint8*)malloc(len);
811 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
817 // Unpack the block of data into a C structure
818 for (i = 0; i < num_fields; i++)
820 switch (fields [i].type)
823 switch (fields [i].size)
826 *((uint8 *) base + fields [i].offset) = *ptr++;
831 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
834 dword = *ptr++ << 24;
835 dword |= *ptr++ << 16;
836 dword |= *ptr++ << 8;
838 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
841 qword = (int64) *ptr++ << 56;
842 qword |= (int64) *ptr++ << 48;
843 qword |= (int64) *ptr++ << 40;
844 qword |= (int64) *ptr++ << 32;
845 qword |= (int64) *ptr++ << 24;
846 qword |= (int64) *ptr++ << 16;
847 qword |= (int64) *ptr++ << 8;
848 qword |= (int64) *ptr++;
849 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
854 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
855 ptr += fields [i].size;
858 for (j = 0; j < fields [i].size; j++)
862 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
866 for (j = 0; j < fields [i].size; j++)
868 dword = *ptr++ << 24;
869 dword |= *ptr++ << 16;
870 dword |= *ptr++ << 8;
872 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
883 int UnfreezeBlock(const char *name, uint8 *block, int size)
889 if (READ_STREAM(buffer, 11, ss_st) != 11 ||
890 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
891 (len = atoi (&buffer [4])) == 0)
893 printf("%s: %s: Invalid block header\n", __func__, name);
903 if (READ_STREAM(block, len, ss_st) != len)
905 printf("%s: Invalid block\n", __func__);
911 char *junk = (char*)malloc(rem);
912 READ_STREAM(junk, rem, ss_st);