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.
59 #include "screenshot.h"
61 #define dprintf(...) /* disabled */
65 void S9xSuperFXPreSaveState ();
66 void S9xSuperFXPostSaveState ();
67 void S9xSuperFXPostLoadState ();
68 //bool8 S9xUnfreezeZSNES (const char *filename);
79 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
82 #define Offset(field,structure) \
83 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
85 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
88 #define OFFSET(f) Offset(f,struct SCPUState *)
90 static FreezeData SnapCPU [] = {
91 {OFFSET (Flags), 4, INT_V},
92 {OFFSET (BranchSkip), 1, INT_V},
93 {OFFSET (NMIActive), 1, INT_V},
94 {OFFSET (IRQActive), 1, INT_V},
95 {OFFSET (WaitingForInterrupt), 1, INT_V},
96 {OFFSET (WhichEvent), 1, INT_V},
97 {OFFSET (Cycles), 4, INT_V},
98 {OFFSET (NextEvent), 4, INT_V},
99 {OFFSET (V_Counter), 4, INT_V},
100 {OFFSET (MemSpeed), 4, INT_V},
101 {OFFSET (MemSpeedx2), 4, INT_V},
102 {OFFSET (FastROMSpeed), 4, INT_V}
106 #define OFFSET(f) Offset(f,struct SRegisters *)
108 static FreezeData SnapRegisters [] = {
109 {OFFSET (PB), 1, INT_V},
110 {OFFSET (DB), 1, INT_V},
111 {OFFSET (P.W), 2, INT_V},
112 {OFFSET (A.W), 2, INT_V},
113 {OFFSET (D.W), 2, INT_V},
114 {OFFSET (S.W), 2, INT_V},
115 {OFFSET (X.W), 2, INT_V},
116 {OFFSET (Y.W), 2, INT_V},
117 {OFFSET (PC), 2, INT_V}
121 #define OFFSET(f) Offset(f,struct SPPU *)
123 static FreezeData SnapPPU [] = {
124 {OFFSET (BGMode), 1, INT_V},
125 {OFFSET (BG3Priority), 1, INT_V},
126 {OFFSET (Brightness), 1, INT_V},
127 {OFFSET (VMA.High), 1, INT_V},
128 {OFFSET (VMA.Increment), 1, INT_V},
129 {OFFSET (VMA.Address), 2, INT_V},
130 {OFFSET (VMA.Mask1), 2, INT_V},
131 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
132 {OFFSET (VMA.Shift), 2, INT_V},
133 {OFFSET (BG[0].SCBase), 2, INT_V},
134 {OFFSET (BG[0].VOffset), 2, INT_V},
135 {OFFSET (BG[0].HOffset), 2, INT_V},
136 {OFFSET (BG[0].BGSize), 1, INT_V},
137 {OFFSET (BG[0].NameBase), 2, INT_V},
138 {OFFSET (BG[0].SCSize), 2, INT_V},
140 {OFFSET (BG[1].SCBase), 2, INT_V},
141 {OFFSET (BG[1].VOffset), 2, INT_V},
142 {OFFSET (BG[1].HOffset), 2, INT_V},
143 {OFFSET (BG[1].BGSize), 1, INT_V},
144 {OFFSET (BG[1].NameBase), 2, INT_V},
145 {OFFSET (BG[1].SCSize), 2, INT_V},
147 {OFFSET (BG[2].SCBase), 2, INT_V},
148 {OFFSET (BG[2].VOffset), 2, INT_V},
149 {OFFSET (BG[2].HOffset), 2, INT_V},
150 {OFFSET (BG[2].BGSize), 1, INT_V},
151 {OFFSET (BG[2].NameBase), 2, INT_V},
152 {OFFSET (BG[2].SCSize), 2, INT_V},
154 {OFFSET (BG[3].SCBase), 2, INT_V},
155 {OFFSET (BG[3].VOffset), 2, INT_V},
156 {OFFSET (BG[3].HOffset), 2, INT_V},
157 {OFFSET (BG[3].BGSize), 1, INT_V},
158 {OFFSET (BG[3].NameBase), 2, INT_V},
159 {OFFSET (BG[3].SCSize), 2, INT_V},
161 {OFFSET (CGFLIP), 1, INT_V},
162 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
163 {OFFSET (FirstSprite), 1, INT_V},
165 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
166 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
167 {OFFSET (OBJ[N].Name), 2, INT_V}, \
168 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
169 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
170 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
171 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
172 {OFFSET (OBJ[N].Size), 1, INT_V}
174 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
175 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
176 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
177 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
178 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
179 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
180 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
181 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
182 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
183 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
184 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
185 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
186 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
187 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
188 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
189 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
191 {OFFSET (OAMPriorityRotation), 1, INT_V},
192 {OFFSET (OAMAddr), 2, INT_V},
193 {OFFSET (OAMFlip), 1, INT_V},
194 {OFFSET (OAMTileAddress), 2, INT_V},
195 {OFFSET (IRQVBeamPos), 2, INT_V},
196 {OFFSET (IRQHBeamPos), 2, INT_V},
197 {OFFSET (VBeamPosLatched), 2, INT_V},
198 {OFFSET (HBeamPosLatched), 2, INT_V},
199 {OFFSET (HBeamFlip), 1, INT_V},
200 {OFFSET (VBeamFlip), 1, INT_V},
201 {OFFSET (HVBeamCounterLatched), 1, INT_V},
202 {OFFSET (MatrixA), 2, INT_V},
203 {OFFSET (MatrixB), 2, INT_V},
204 {OFFSET (MatrixC), 2, INT_V},
205 {OFFSET (MatrixD), 2, INT_V},
206 {OFFSET (CentreX), 2, INT_V},
207 {OFFSET (CentreY), 2, INT_V},
208 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
209 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
210 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
211 {OFFSET (CGADD), 1, INT_V},
212 {OFFSET (FixedColourRed), 1, INT_V},
213 {OFFSET (FixedColourGreen), 1, INT_V},
214 {OFFSET (FixedColourBlue), 1, INT_V},
215 {OFFSET (SavedOAMAddr), 2, INT_V},
216 {OFFSET (ScreenHeight), 2, INT_V},
217 {OFFSET (WRAM), 4, INT_V},
218 {OFFSET (ForcedBlanking), 1, INT_V},
219 {OFFSET (OBJNameSelect), 2, INT_V},
220 {OFFSET (OBJSizeSelect), 1, INT_V},
221 {OFFSET (OBJNameBase), 2, INT_V},
222 {OFFSET (OAMReadFlip), 1, INT_V},
223 {OFFSET (VTimerEnabled), 1, INT_V},
224 {OFFSET (HTimerEnabled), 1, INT_V},
225 {OFFSET (HTimerPosition), 2, INT_V},
226 {OFFSET (Mosaic), 1, INT_V},
227 {OFFSET (Mode7HFlip), 1, INT_V},
228 {OFFSET (Mode7VFlip), 1, INT_V},
229 {OFFSET (Mode7Repeat), 1, INT_V},
230 {OFFSET (Window1Left), 1, INT_V},
231 {OFFSET (Window1Right), 1, INT_V},
232 {OFFSET (Window2Left), 1, INT_V},
233 {OFFSET (Window2Right), 1, INT_V},
235 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
236 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
237 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
238 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
239 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
241 O(0), O(1), O(2), O(3), O(4), O(5),
245 {OFFSET (CGFLIPRead), 1, INT_V},
246 {OFFSET (Need16x8Mulitply), 1, INT_V},
247 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
248 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
249 {OFFSET (Need16x8Mulitply), 1, INT_V},
250 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
254 #define OFFSET(f) Offset(f,struct SDMA *)
256 static FreezeData SnapDMA [] = {
258 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
259 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
260 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
261 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
262 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
263 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
264 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
265 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
266 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
267 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
268 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
269 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
270 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
271 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
272 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
274 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
279 #define OFFSET(f) Offset(f,struct SAPU *)
281 static FreezeData SnapAPU [] = {
282 {OFFSET (Cycles), 4, INT_V},
283 {OFFSET (ShowROM), 1, INT_V},
284 {OFFSET (Flags), 1, INT_V},
285 {OFFSET (KeyedChannels), 1, INT_V},
286 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
287 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
288 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
289 {OFFSET (Timer), 3, uint16_ARRAY_V},
290 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
291 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
292 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
296 #define OFFSET(f) Offset(f,struct SAPURegisters *)
298 static FreezeData SnapAPURegisters [] = {
299 {OFFSET (P) , 1, INT_V},
300 {OFFSET (YA.W), 2, INT_V},
301 {OFFSET (X) , 1, INT_V},
302 {OFFSET (S) , 1, INT_V},
303 {OFFSET (PC) , 2, INT_V}
308 #define OFFSET(f) Offset(f,SSoundData *)
310 static FreezeData SnapSoundData [] = {
311 {OFFSET (master_volume_left), 2, INT_V},
312 {OFFSET (master_volume_right), 2, INT_V},
313 {OFFSET (echo_volume_left), 2, INT_V},
314 {OFFSET (echo_volume_right), 2, INT_V},
315 {OFFSET (echo_enable), 4, INT_V},
316 {OFFSET (echo_feedback), 4, INT_V},
317 {OFFSET (echo_ptr), 4, INT_V},
318 {OFFSET (echo_buffer_size), 4, INT_V},
319 {OFFSET (echo_write_enabled), 4, INT_V},
320 {OFFSET (echo_channel_enable), 4, INT_V},
321 {OFFSET (pitch_mod), 4, INT_V},
322 {OFFSET (dummy), 3, uint32_ARRAY_V},
324 {OFFSET (channels [N].state), 4, INT_V}, \
325 {OFFSET (channels [N].type), 4, INT_V}, \
326 {OFFSET (channels [N].volume_left), 2, INT_V}, \
327 {OFFSET (channels [N].volume_right), 2, INT_V}, \
328 {OFFSET (channels [N].hertz), 4, INT_V}, \
329 {OFFSET (channels [N].count), 4, INT_V}, \
330 {OFFSET (channels [N].loop), 1, INT_V}, \
331 {OFFSET (channels [N].envx), 4, INT_V}, \
332 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
333 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
334 {OFFSET (channels [N].envx_target), 2, INT_V}, \
335 {OFFSET (channels [N].env_error), 4, INT_V}, \
336 {OFFSET (channels [N].erate), 4, INT_V}, \
337 {OFFSET (channels [N].direction), 4, INT_V}, \
338 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
339 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
340 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
341 {OFFSET (channels [N].release_rate), 4, INT_V}, \
342 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
343 {OFFSET (channels [N].sample), 2, INT_V}, \
344 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
345 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
346 {OFFSET (channels [N].sample_number), 2, INT_V}, \
347 {OFFSET (channels [N].last_block), 1, INT_V}, \
348 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
349 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
350 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
351 {OFFSET (channels [N].mode), 4, INT_V}
353 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
360 #define OFFSET(f) Offset(f,struct SSA1Registers *)
362 static FreezeData SnapSA1Registers [] = {
363 {OFFSET (PB), 1, INT_V},
364 {OFFSET (DB), 1, INT_V},
365 {OFFSET (P.W), 2, INT_V},
366 {OFFSET (A.W), 2, INT_V},
367 {OFFSET (D.W), 2, INT_V},
368 {OFFSET (S.W), 2, INT_V},
369 {OFFSET (X.W), 2, INT_V},
370 {OFFSET (Y.W), 2, INT_V},
371 {OFFSET (PC), 2, INT_V}
375 #define OFFSET(f) Offset(f,struct SSA1 *)
377 static FreezeData SnapSA1 [] = {
378 {OFFSET (Flags), 4, INT_V},
379 {OFFSET (NMIActive), 1, INT_V},
380 {OFFSET (IRQActive), 1, INT_V},
381 {OFFSET (WaitingForInterrupt), 1, INT_V},
382 {OFFSET (op1), 2, INT_V},
383 {OFFSET (op2), 2, INT_V},
384 {OFFSET (arithmetic_op), 4, INT_V},
385 {OFFSET (sum), 8, INT_V},
386 {OFFSET (overflow), 1, INT_V}
392 static void Freeze ();
393 static int Unfreeze ();
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 ();
516 /* Save a PNG screenshot for convenience. */
518 uint8 *png = (uint8*) S9xScreenshot(&png_size);
520 FreezeBlock("PNG", png, png_size);
526 static int Unfreeze()
529 char rom_filename[1024];
533 int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
534 if (READ_STREAM(buffer, len, ss_st) != len)
536 printf("%s: Failed to read header\n", __func__);
539 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
541 printf("%s: Read header not correct\n", __func__);
544 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
546 printf("%s: Wrong version\n", __func__);
547 return WRONG_VERSION;
550 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
552 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
556 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
557 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
559 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
560 "Current loaded ROM image doesn't match that required by freeze-game file.");
564 uint32 old_flags = CPU.Flags;
566 uint32 sa1_old_flags = SA1.Flags;
569 S9xSetSoundMute (TRUE);
571 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
572 COUNT (SnapCPU))) != SUCCESS)
576 Memory.FixROMSpeed ();
577 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
578 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
579 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
581 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
585 IPPU.ColorsChanged = TRUE;
586 IPPU.OBJChanged = TRUE;
588 S9xFixColourBrightness ();
589 IPPU.RenderThisFrame = FALSE;
591 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
592 COUNT (SnapDMA))) != SUCCESS)
595 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
598 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
601 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
604 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
608 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
610 SAPURegisters spcregs;
611 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
612 COUNT (SnapAPURegisters))) != SUCCESS)
614 // reload all SPC700 regs from savestate compatible struct
616 IAPU.YA.W = spcregs.YA.W;
619 IAPU.PC = IAPU.RAM + spcregs.PC;
621 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
624 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
625 COUNT (SnapSoundData))) != SUCCESS)
628 // notaz: just to be sure
629 for(int u=0; u<8; u++) {
630 SoundData.channels[u].env_ind_attack &= 0xf;
631 SoundData.channels[u].env_ind_decay &= 0x7;
632 SoundData.channels[u].env_ind_sustain&= 0x1f;
635 S9xSetSoundMute (FALSE);
636 S9xAPUUnpackStatus ();
637 if (APUCheckDirectPage ())
638 IAPU.DirectPage = IAPU.RAM + 0x100;
640 IAPU.DirectPage = IAPU.RAM;
641 Settings.APUEnabled = TRUE;
642 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
646 Settings.APUEnabled = FALSE;
647 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
648 S9xSetSoundMute (TRUE);
651 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
652 COUNT(SnapSA1))) == SUCCESS)
654 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
655 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
658 S9xFixSA1AfterSnapshotLoad ();
659 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
662 S9xFixSoundAfterSnapshotLoad ();
663 ICPU.ShiftedPB = Registers.PB << 16;
664 ICPU.ShiftedDB = Registers.DB << 16;
665 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
667 #if !CONF_BUILD_ASM_CPU
674 if (Settings.SuperFX)
675 S9xSuperFXPostLoadState ();
678 S9xSRTCPostLoadState ();
679 if (Settings.SDD1) S9xSDD1PostLoadState ();
684 static int FreezeSize (int size, int type)
697 void FreezeStruct(const char *name, void *base, FreezeData *fields,
700 // Work out the size of the required block
705 for (i = 0; i < num_fields; i++)
707 if (fields [i].offset + FreezeSize (fields [i].size,
708 fields [i].type) > len)
709 len = fields [i].offset + FreezeSize (fields [i].size,
713 uint8 *block = new uint8[len];
719 // Build the block ready to be streamed out
720 for (i = 0; i < num_fields; i++)
722 switch (fields [i].type)
725 switch (fields [i].size)
728 *ptr++ = *((uint8 *) base + fields [i].offset);
731 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
732 *ptr++ = (uint8) (word >> 8);
733 *ptr++ = (uint8) word;
736 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
737 *ptr++ = (uint8) (dword >> 24);
738 *ptr++ = (uint8) (dword >> 16);
739 *ptr++ = (uint8) (dword >> 8);
740 *ptr++ = (uint8) dword;
743 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
744 *ptr++ = (uint8) (qword >> 56);
745 *ptr++ = (uint8) (qword >> 48);
746 *ptr++ = (uint8) (qword >> 40);
747 *ptr++ = (uint8) (qword >> 32);
748 *ptr++ = (uint8) (qword >> 24);
749 *ptr++ = (uint8) (qword >> 16);
750 *ptr++ = (uint8) (qword >> 8);
751 *ptr++ = (uint8) qword;
756 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
757 ptr += fields [i].size;
760 for (j = 0; j < fields [i].size; j++)
762 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
763 *ptr++ = (uint8) (word >> 8);
764 *ptr++ = (uint8) word;
768 for (j = 0; j < fields [i].size; j++)
770 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
771 *ptr++ = (uint8) (dword >> 24);
772 *ptr++ = (uint8) (dword >> 16);
773 *ptr++ = (uint8) (dword >> 8);
774 *ptr++ = (uint8) dword;
780 FreezeBlock (name, block, len);
785 void FreezeBlock (const char *name, uint8 *block, int size)
788 sprintf (buffer, "%s:%06d:", name, size);
789 WRITE_STREAM(buffer, strlen(buffer), ss_st);
790 WRITE_STREAM(block, size, ss_st);
793 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
796 // Work out the size of the required block
801 for (i = 0; i < num_fields; i++)
803 if (fields [i].offset + FreezeSize (fields [i].size,
804 fields [i].type) > len)
805 len = fields [i].offset + FreezeSize (fields [i].size,
809 uint8 *block = new uint8 [len];
816 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
822 // Unpack the block of data into a C structure
823 for (i = 0; i < num_fields; i++)
825 switch (fields [i].type)
828 switch (fields [i].size)
831 *((uint8 *) base + fields [i].offset) = *ptr++;
836 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
839 dword = *ptr++ << 24;
840 dword |= *ptr++ << 16;
841 dword |= *ptr++ << 8;
843 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
846 qword = (int64) *ptr++ << 56;
847 qword |= (int64) *ptr++ << 48;
848 qword |= (int64) *ptr++ << 40;
849 qword |= (int64) *ptr++ << 32;
850 qword |= (int64) *ptr++ << 24;
851 qword |= (int64) *ptr++ << 16;
852 qword |= (int64) *ptr++ << 8;
853 qword |= (int64) *ptr++;
854 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
859 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
860 ptr += fields [i].size;
863 for (j = 0; j < fields [i].size; j++)
867 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
871 for (j = 0; j < fields [i].size; j++)
873 dword = *ptr++ << 24;
874 dword |= *ptr++ << 16;
875 dword |= *ptr++ << 8;
877 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
888 int UnfreezeBlock(const char *name, uint8 *block, int size)
894 if (READ_STREAM(buffer, 11, ss_st) != 11 ||
895 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
896 (len = atoi (&buffer [4])) == 0)
898 dprintf("%s: %s: Invalid block header\n", __func__, name);
908 if (READ_STREAM(block, len, ss_st) != len)
910 dprintf("%s: Invalid block\n", __func__);
916 char *junk = new char [rem];
917 READ_STREAM(junk, rem, ss_st);