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.
60 #define dprintf(...) /* disabled */
64 void S9xSuperFXPreSaveState ();
65 void S9xSuperFXPostSaveState ();
66 void S9xSuperFXPostLoadState ();
67 //bool8 S9xUnfreezeZSNES (const char *filename);
78 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
81 #define Offset(field,structure) \
82 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
84 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
87 #define OFFSET(f) Offset(f,struct SCPUState *)
89 static FreezeData SnapCPU [] = {
90 {OFFSET (Flags), 4, INT_V},
91 {OFFSET (BranchSkip), 1, INT_V},
92 {OFFSET (NMIActive), 1, INT_V},
93 {OFFSET (IRQActive), 1, INT_V},
94 {OFFSET (WaitingForInterrupt), 1, INT_V},
95 {OFFSET (WhichEvent), 1, INT_V},
96 {OFFSET (Cycles), 4, INT_V},
97 {OFFSET (NextEvent), 4, INT_V},
98 {OFFSET (V_Counter), 4, INT_V},
99 {OFFSET (MemSpeed), 4, INT_V},
100 {OFFSET (MemSpeedx2), 4, INT_V},
101 {OFFSET (FastROMSpeed), 4, INT_V}
105 #define OFFSET(f) Offset(f,struct SRegisters *)
107 static FreezeData SnapRegisters [] = {
108 {OFFSET (PB), 1, INT_V},
109 {OFFSET (DB), 1, INT_V},
110 {OFFSET (P.W), 2, INT_V},
111 {OFFSET (A.W), 2, INT_V},
112 {OFFSET (D.W), 2, INT_V},
113 {OFFSET (S.W), 2, INT_V},
114 {OFFSET (X.W), 2, INT_V},
115 {OFFSET (Y.W), 2, INT_V},
116 {OFFSET (PC), 2, INT_V}
120 #define OFFSET(f) Offset(f,struct SPPU *)
122 static FreezeData SnapPPU [] = {
123 {OFFSET (BGMode), 1, INT_V},
124 {OFFSET (BG3Priority), 1, INT_V},
125 {OFFSET (Brightness), 1, INT_V},
126 {OFFSET (VMA.High), 1, INT_V},
127 {OFFSET (VMA.Increment), 1, INT_V},
128 {OFFSET (VMA.Address), 2, INT_V},
129 {OFFSET (VMA.Mask1), 2, INT_V},
130 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
131 {OFFSET (VMA.Shift), 2, INT_V},
132 {OFFSET (BG[0].SCBase), 2, INT_V},
133 {OFFSET (BG[0].VOffset), 2, INT_V},
134 {OFFSET (BG[0].HOffset), 2, INT_V},
135 {OFFSET (BG[0].BGSize), 1, INT_V},
136 {OFFSET (BG[0].NameBase), 2, INT_V},
137 {OFFSET (BG[0].SCSize), 2, INT_V},
139 {OFFSET (BG[1].SCBase), 2, INT_V},
140 {OFFSET (BG[1].VOffset), 2, INT_V},
141 {OFFSET (BG[1].HOffset), 2, INT_V},
142 {OFFSET (BG[1].BGSize), 1, INT_V},
143 {OFFSET (BG[1].NameBase), 2, INT_V},
144 {OFFSET (BG[1].SCSize), 2, INT_V},
146 {OFFSET (BG[2].SCBase), 2, INT_V},
147 {OFFSET (BG[2].VOffset), 2, INT_V},
148 {OFFSET (BG[2].HOffset), 2, INT_V},
149 {OFFSET (BG[2].BGSize), 1, INT_V},
150 {OFFSET (BG[2].NameBase), 2, INT_V},
151 {OFFSET (BG[2].SCSize), 2, INT_V},
153 {OFFSET (BG[3].SCBase), 2, INT_V},
154 {OFFSET (BG[3].VOffset), 2, INT_V},
155 {OFFSET (BG[3].HOffset), 2, INT_V},
156 {OFFSET (BG[3].BGSize), 1, INT_V},
157 {OFFSET (BG[3].NameBase), 2, INT_V},
158 {OFFSET (BG[3].SCSize), 2, INT_V},
160 {OFFSET (CGFLIP), 1, INT_V},
161 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
162 {OFFSET (FirstSprite), 1, INT_V},
164 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
165 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
166 {OFFSET (OBJ[N].Name), 2, INT_V}, \
167 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
168 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
169 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
170 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
171 {OFFSET (OBJ[N].Size), 1, INT_V}
173 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
174 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
175 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
176 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
177 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
178 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
179 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
180 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
181 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
182 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
183 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
184 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
185 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
186 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
187 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
188 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
190 {OFFSET (OAMPriorityRotation), 1, INT_V},
191 {OFFSET (OAMAddr), 2, INT_V},
192 {OFFSET (OAMFlip), 1, INT_V},
193 {OFFSET (OAMTileAddress), 2, INT_V},
194 {OFFSET (IRQVBeamPos), 2, INT_V},
195 {OFFSET (IRQHBeamPos), 2, INT_V},
196 {OFFSET (VBeamPosLatched), 2, INT_V},
197 {OFFSET (HBeamPosLatched), 2, INT_V},
198 {OFFSET (HBeamFlip), 1, INT_V},
199 {OFFSET (VBeamFlip), 1, INT_V},
200 {OFFSET (HVBeamCounterLatched), 1, INT_V},
201 {OFFSET (MatrixA), 2, INT_V},
202 {OFFSET (MatrixB), 2, INT_V},
203 {OFFSET (MatrixC), 2, INT_V},
204 {OFFSET (MatrixD), 2, INT_V},
205 {OFFSET (CentreX), 2, INT_V},
206 {OFFSET (CentreY), 2, INT_V},
207 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
208 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
209 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
210 {OFFSET (CGADD), 1, INT_V},
211 {OFFSET (FixedColourRed), 1, INT_V},
212 {OFFSET (FixedColourGreen), 1, INT_V},
213 {OFFSET (FixedColourBlue), 1, INT_V},
214 {OFFSET (SavedOAMAddr), 2, INT_V},
215 {OFFSET (ScreenHeight), 2, INT_V},
216 {OFFSET (WRAM), 4, INT_V},
217 {OFFSET (ForcedBlanking), 1, INT_V},
218 {OFFSET (OBJNameSelect), 2, INT_V},
219 {OFFSET (OBJSizeSelect), 1, INT_V},
220 {OFFSET (OBJNameBase), 2, INT_V},
221 {OFFSET (OAMReadFlip), 1, INT_V},
222 {OFFSET (VTimerEnabled), 1, INT_V},
223 {OFFSET (HTimerEnabled), 1, INT_V},
224 {OFFSET (HTimerPosition), 2, INT_V},
225 {OFFSET (Mosaic), 1, INT_V},
226 {OFFSET (Mode7HFlip), 1, INT_V},
227 {OFFSET (Mode7VFlip), 1, INT_V},
228 {OFFSET (Mode7Repeat), 1, INT_V},
229 {OFFSET (Window1Left), 1, INT_V},
230 {OFFSET (Window1Right), 1, INT_V},
231 {OFFSET (Window2Left), 1, INT_V},
232 {OFFSET (Window2Right), 1, INT_V},
234 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
235 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
236 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
237 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
238 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
240 O(0), O(1), O(2), O(3), O(4), O(5),
244 {OFFSET (CGFLIPRead), 1, INT_V},
245 {OFFSET (Need16x8Mulitply), 1, INT_V},
246 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
247 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
248 {OFFSET (Need16x8Mulitply), 1, INT_V},
249 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
253 #define OFFSET(f) Offset(f,struct SDMA *)
255 static FreezeData SnapDMA [] = {
257 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
258 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
259 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
260 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
261 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
262 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
263 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
264 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
265 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
266 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
267 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
268 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
269 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
270 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
271 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
273 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
278 #define OFFSET(f) Offset(f,struct SAPU *)
280 static FreezeData SnapAPU [] = {
281 {OFFSET (Cycles), 4, INT_V},
282 {OFFSET (ShowROM), 1, INT_V},
283 {OFFSET (Flags), 1, INT_V},
284 {OFFSET (KeyedChannels), 1, INT_V},
285 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
286 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
287 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
288 {OFFSET (Timer), 3, uint16_ARRAY_V},
289 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
290 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
291 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
295 #define OFFSET(f) Offset(f,struct SAPURegisters *)
297 static FreezeData SnapAPURegisters [] = {
298 {OFFSET (P) , 1, INT_V},
299 {OFFSET (YA.W), 2, INT_V},
300 {OFFSET (X) , 1, INT_V},
301 {OFFSET (S) , 1, INT_V},
302 {OFFSET (PC) , 2, INT_V}
307 #define OFFSET(f) Offset(f,SSoundData *)
309 static FreezeData SnapSoundData [] = {
310 {OFFSET (master_volume_left), 2, INT_V},
311 {OFFSET (master_volume_right), 2, INT_V},
312 {OFFSET (echo_volume_left), 2, INT_V},
313 {OFFSET (echo_volume_right), 2, INT_V},
314 {OFFSET (echo_enable), 4, INT_V},
315 {OFFSET (echo_feedback), 4, INT_V},
316 {OFFSET (echo_ptr), 4, INT_V},
317 {OFFSET (echo_buffer_size), 4, INT_V},
318 {OFFSET (echo_write_enabled), 4, INT_V},
319 {OFFSET (echo_channel_enable), 4, INT_V},
320 {OFFSET (pitch_mod), 4, INT_V},
321 {OFFSET (dummy), 3, uint32_ARRAY_V},
323 {OFFSET (channels [N].state), 4, INT_V}, \
324 {OFFSET (channels [N].type), 4, INT_V}, \
325 {OFFSET (channels [N].volume_left), 2, INT_V}, \
326 {OFFSET (channels [N].volume_right), 2, INT_V}, \
327 {OFFSET (channels [N].hertz), 4, INT_V}, \
328 {OFFSET (channels [N].count), 4, INT_V}, \
329 {OFFSET (channels [N].loop), 1, INT_V}, \
330 {OFFSET (channels [N].envx), 4, INT_V}, \
331 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
332 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
333 {OFFSET (channels [N].envx_target), 2, INT_V}, \
334 {OFFSET (channels [N].env_error), 4, INT_V}, \
335 {OFFSET (channels [N].erate), 4, INT_V}, \
336 {OFFSET (channels [N].direction), 4, INT_V}, \
337 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
338 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
339 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
340 {OFFSET (channels [N].release_rate), 4, INT_V}, \
341 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
342 {OFFSET (channels [N].sample), 2, INT_V}, \
343 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
344 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
345 {OFFSET (channels [N].sample_number), 2, INT_V}, \
346 {OFFSET (channels [N].last_block), 1, INT_V}, \
347 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
348 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
349 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
350 {OFFSET (channels [N].mode), 4, INT_V}
352 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
359 #define OFFSET(f) Offset(f,struct SSA1Registers *)
361 static FreezeData SnapSA1Registers [] = {
362 {OFFSET (PB), 1, INT_V},
363 {OFFSET (DB), 1, INT_V},
364 {OFFSET (P.W), 2, INT_V},
365 {OFFSET (A.W), 2, INT_V},
366 {OFFSET (D.W), 2, INT_V},
367 {OFFSET (S.W), 2, INT_V},
368 {OFFSET (X.W), 2, INT_V},
369 {OFFSET (Y.W), 2, INT_V},
370 {OFFSET (PC), 2, INT_V}
374 #define OFFSET(f) Offset(f,struct SSA1 *)
376 static FreezeData SnapSA1 [] = {
377 {OFFSET (Flags), 4, INT_V},
378 {OFFSET (NMIActive), 1, INT_V},
379 {OFFSET (IRQActive), 1, INT_V},
380 {OFFSET (WaitingForInterrupt), 1, INT_V},
381 {OFFSET (op1), 2, INT_V},
382 {OFFSET (op2), 2, INT_V},
383 {OFFSET (arithmetic_op), 4, INT_V},
384 {OFFSET (sum), 8, INT_V},
385 {OFFSET (overflow), 1, INT_V}
391 static void Freeze ();
392 static int Unfreeze ();
394 static void FreezeSnapshot (const char *name);
395 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
397 static void FreezeBlock (const char *name, uint8 *block, int size);
399 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
401 static int UnfreezeBlock (const char *name, uint8 *block, int size);
403 bool8 S9xFreezeGame (const char *filename)
405 if ((ss_st = OPEN_STREAM(filename, "wb")))
415 bool8 S9xUnfreezeGame (const char *filename)
417 if ((ss_st = OPEN_STREAM(filename, "rb")))
420 if ((result = Unfreeze()) != SUCCESS)
425 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
426 "File not in Snes9x freeze format");
430 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
431 "Incompatable Snes9x freeze file format version");
435 // should never happen
449 static void Freeze ()
454 S9xSetSoundMute (TRUE);
456 if (Settings.SuperFX)
457 S9xSuperFXPreSaveState ();
460 S9xSRTCPreSaveState ();
462 for (i = 0; i < 8; i++)
464 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
465 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
467 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
468 WRITE_STREAM(buffer, strlen(buffer), ss_st);
469 sprintf (buffer, "NAM:%06zu:%s%c", strlen(Memory.ROMFilename) + 1,
470 Memory.ROMFilename, 0);
471 WRITE_STREAM(buffer, strlen(buffer) + 1, ss_st);
472 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
473 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
474 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
475 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
478 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
479 FreezeBlock ("RAM", Memory.RAM, 0x20000);
480 FreezeBlock ("SRA", ::SRAM, 0x20000);
481 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
482 if (Settings.APUEnabled)
485 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
486 // copy all SPC700 regs to savestate compatible struct
487 SAPURegisters spcregs;
489 spcregs.YA.W = IAPU.YA.W;
492 spcregs.PC = IAPU.PC - IAPU.RAM;
493 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
494 COUNT (SnapAPURegisters));
496 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
497 FreezeStruct ("SOU", &SoundData, SnapSoundData,
498 COUNT (SnapSoundData));
503 SA1Registers.PC = SA1.PC - SA1.PCBase;
505 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
506 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
507 COUNT (SnapSA1Registers));
510 S9xSetSoundMute (FALSE);
512 if (Settings.SuperFX)
513 S9xSuperFXPostSaveState ();
517 static int Unfreeze()
520 char rom_filename[1024];
524 int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
525 if (READ_STREAM(buffer, len, ss_st) != len)
527 printf("%s: Failed to read header\n", __func__);
530 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
532 printf("%s: Read header not correct\n", __func__);
535 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
537 printf("%s: Wrong version\n", __func__);
538 return WRONG_VERSION;
541 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
543 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
547 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
548 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
550 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
551 "Current loaded ROM image doesn't match that required by freeze-game file.");
555 uint32 old_flags = CPU.Flags;
557 uint32 sa1_old_flags = SA1.Flags;
560 S9xSetSoundMute (TRUE);
562 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
563 COUNT (SnapCPU))) != SUCCESS)
567 Memory.FixROMSpeed ();
568 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
569 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
570 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
572 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
576 IPPU.ColorsChanged = TRUE;
577 IPPU.OBJChanged = TRUE;
579 S9xFixColourBrightness ();
580 IPPU.RenderThisFrame = FALSE;
582 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
583 COUNT (SnapDMA))) != SUCCESS)
586 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
589 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
592 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
595 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
599 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
601 SAPURegisters spcregs;
602 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
603 COUNT (SnapAPURegisters))) != SUCCESS)
605 // reload all SPC700 regs from savestate compatible struct
607 IAPU.YA.W = spcregs.YA.W;
610 IAPU.PC = IAPU.RAM + spcregs.PC;
612 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
615 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
616 COUNT (SnapSoundData))) != SUCCESS)
619 // notaz: just to be sure
620 for(int u=0; u<8; u++) {
621 SoundData.channels[u].env_ind_attack &= 0xf;
622 SoundData.channels[u].env_ind_decay &= 0x7;
623 SoundData.channels[u].env_ind_sustain&= 0x1f;
626 S9xSetSoundMute (FALSE);
627 S9xAPUUnpackStatus ();
628 if (APUCheckDirectPage ())
629 IAPU.DirectPage = IAPU.RAM + 0x100;
631 IAPU.DirectPage = IAPU.RAM;
632 Settings.APUEnabled = TRUE;
633 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
637 Settings.APUEnabled = FALSE;
638 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
639 S9xSetSoundMute (TRUE);
642 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
643 COUNT(SnapSA1))) == SUCCESS)
645 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
646 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
649 S9xFixSA1AfterSnapshotLoad ();
650 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
653 S9xFixSoundAfterSnapshotLoad ();
654 ICPU.ShiftedPB = Registers.PB << 16;
655 ICPU.ShiftedDB = Registers.DB << 16;
656 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
658 #if !CONF_BUILD_ASM_CPU
665 if (Settings.SuperFX)
666 S9xSuperFXPostLoadState ();
669 S9xSRTCPostLoadState ();
670 if (Settings.SDD1) S9xSDD1PostLoadState ();
675 static int FreezeSize (int size, int type)
688 void FreezeStruct(const char *name, void *base, FreezeData *fields,
691 // Work out the size of the required block
696 for (i = 0; i < num_fields; i++)
698 if (fields [i].offset + FreezeSize (fields [i].size,
699 fields [i].type) > len)
700 len = fields [i].offset + FreezeSize (fields [i].size,
704 uint8 *block = new uint8[len];
710 // Build the block ready to be streamed out
711 for (i = 0; i < num_fields; i++)
713 switch (fields [i].type)
716 switch (fields [i].size)
719 *ptr++ = *((uint8 *) base + fields [i].offset);
722 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
723 *ptr++ = (uint8) (word >> 8);
724 *ptr++ = (uint8) word;
727 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
728 *ptr++ = (uint8) (dword >> 24);
729 *ptr++ = (uint8) (dword >> 16);
730 *ptr++ = (uint8) (dword >> 8);
731 *ptr++ = (uint8) dword;
734 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
735 *ptr++ = (uint8) (qword >> 56);
736 *ptr++ = (uint8) (qword >> 48);
737 *ptr++ = (uint8) (qword >> 40);
738 *ptr++ = (uint8) (qword >> 32);
739 *ptr++ = (uint8) (qword >> 24);
740 *ptr++ = (uint8) (qword >> 16);
741 *ptr++ = (uint8) (qword >> 8);
742 *ptr++ = (uint8) qword;
747 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
748 ptr += fields [i].size;
751 for (j = 0; j < fields [i].size; j++)
753 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
754 *ptr++ = (uint8) (word >> 8);
755 *ptr++ = (uint8) word;
759 for (j = 0; j < fields [i].size; j++)
761 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
762 *ptr++ = (uint8) (dword >> 24);
763 *ptr++ = (uint8) (dword >> 16);
764 *ptr++ = (uint8) (dword >> 8);
765 *ptr++ = (uint8) dword;
771 FreezeBlock (name, block, len);
776 void FreezeBlock (const char *name, uint8 *block, int size)
779 sprintf (buffer, "%s:%06d:", name, size);
780 WRITE_STREAM(buffer, strlen(buffer), ss_st);
781 WRITE_STREAM(block, size, ss_st);
784 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
787 // Work out the size of the required block
792 for (i = 0; i < num_fields; i++)
794 if (fields [i].offset + FreezeSize (fields [i].size,
795 fields [i].type) > len)
796 len = fields [i].offset + FreezeSize (fields [i].size,
800 uint8 *block = new uint8 [len];
807 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
813 // Unpack the block of data into a C structure
814 for (i = 0; i < num_fields; i++)
816 switch (fields [i].type)
819 switch (fields [i].size)
822 *((uint8 *) base + fields [i].offset) = *ptr++;
827 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
830 dword = *ptr++ << 24;
831 dword |= *ptr++ << 16;
832 dword |= *ptr++ << 8;
834 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
837 qword = (int64) *ptr++ << 56;
838 qword |= (int64) *ptr++ << 48;
839 qword |= (int64) *ptr++ << 40;
840 qword |= (int64) *ptr++ << 32;
841 qword |= (int64) *ptr++ << 24;
842 qword |= (int64) *ptr++ << 16;
843 qword |= (int64) *ptr++ << 8;
844 qword |= (int64) *ptr++;
845 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
850 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
851 ptr += fields [i].size;
854 for (j = 0; j < fields [i].size; j++)
858 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
862 for (j = 0; j < fields [i].size; j++)
864 dword = *ptr++ << 24;
865 dword |= *ptr++ << 16;
866 dword |= *ptr++ << 8;
868 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
879 int UnfreezeBlock(const char *name, uint8 *block, int size)
885 if (READ_STREAM(buffer, 11, ss_st) != 11 ||
886 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
887 (len = atoi (&buffer [4])) == 0)
889 dprintf("%s: %s: Invalid block header\n", __func__, name);
899 if (READ_STREAM(block, len, ss_st) != len)
901 dprintf("%s: Invalid block\n", __func__);
907 char *junk = (char*)malloc(rem);
908 READ_STREAM(junk, rem, ss_st);