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>
67 #define dprintf(...) /* disabled */
73 void S9xSuperFXPreSaveState ();
74 void S9xSuperFXPostSaveState ();
75 void S9xSuperFXPostLoadState ();
76 //bool8 S9xUnfreezeZSNES (const char *filename);
87 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
90 #define Offset(field,structure) \
91 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
93 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
96 #define OFFSET(f) Offset(f,struct SCPUState *)
98 static FreezeData SnapCPU [] = {
99 {OFFSET (Flags), 4, INT_V},
100 {OFFSET (BranchSkip), 1, INT_V},
101 {OFFSET (NMIActive), 1, INT_V},
102 {OFFSET (IRQActive), 1, INT_V},
103 {OFFSET (WaitingForInterrupt), 1, INT_V},
104 {OFFSET (WhichEvent), 1, INT_V},
105 {OFFSET (Cycles), 4, INT_V},
106 {OFFSET (NextEvent), 4, INT_V},
107 {OFFSET (V_Counter), 4, INT_V},
108 {OFFSET (MemSpeed), 4, INT_V},
109 {OFFSET (MemSpeedx2), 4, INT_V},
110 {OFFSET (FastROMSpeed), 4, INT_V}
114 #define OFFSET(f) Offset(f,struct SRegisters *)
116 static FreezeData SnapRegisters [] = {
117 {OFFSET (PB), 1, INT_V},
118 {OFFSET (DB), 1, INT_V},
119 {OFFSET (P.W), 2, INT_V},
120 {OFFSET (A.W), 2, INT_V},
121 {OFFSET (D.W), 2, INT_V},
122 {OFFSET (S.W), 2, INT_V},
123 {OFFSET (X.W), 2, INT_V},
124 {OFFSET (Y.W), 2, INT_V},
125 {OFFSET (PC), 2, INT_V}
129 #define OFFSET(f) Offset(f,struct SPPU *)
131 static FreezeData SnapPPU [] = {
132 {OFFSET (BGMode), 1, INT_V},
133 {OFFSET (BG3Priority), 1, INT_V},
134 {OFFSET (Brightness), 1, INT_V},
135 {OFFSET (VMA.High), 1, INT_V},
136 {OFFSET (VMA.Increment), 1, INT_V},
137 {OFFSET (VMA.Address), 2, INT_V},
138 {OFFSET (VMA.Mask1), 2, INT_V},
139 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
140 {OFFSET (VMA.Shift), 2, INT_V},
141 {OFFSET (BG[0].SCBase), 2, INT_V},
142 {OFFSET (BG[0].VOffset), 2, INT_V},
143 {OFFSET (BG[0].HOffset), 2, INT_V},
144 {OFFSET (BG[0].BGSize), 1, INT_V},
145 {OFFSET (BG[0].NameBase), 2, INT_V},
146 {OFFSET (BG[0].SCSize), 2, INT_V},
148 {OFFSET (BG[1].SCBase), 2, INT_V},
149 {OFFSET (BG[1].VOffset), 2, INT_V},
150 {OFFSET (BG[1].HOffset), 2, INT_V},
151 {OFFSET (BG[1].BGSize), 1, INT_V},
152 {OFFSET (BG[1].NameBase), 2, INT_V},
153 {OFFSET (BG[1].SCSize), 2, INT_V},
155 {OFFSET (BG[2].SCBase), 2, INT_V},
156 {OFFSET (BG[2].VOffset), 2, INT_V},
157 {OFFSET (BG[2].HOffset), 2, INT_V},
158 {OFFSET (BG[2].BGSize), 1, INT_V},
159 {OFFSET (BG[2].NameBase), 2, INT_V},
160 {OFFSET (BG[2].SCSize), 2, INT_V},
162 {OFFSET (BG[3].SCBase), 2, INT_V},
163 {OFFSET (BG[3].VOffset), 2, INT_V},
164 {OFFSET (BG[3].HOffset), 2, INT_V},
165 {OFFSET (BG[3].BGSize), 1, INT_V},
166 {OFFSET (BG[3].NameBase), 2, INT_V},
167 {OFFSET (BG[3].SCSize), 2, INT_V},
169 {OFFSET (CGFLIP), 1, INT_V},
170 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
171 {OFFSET (FirstSprite), 1, INT_V},
173 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
174 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
175 {OFFSET (OBJ[N].Name), 2, INT_V}, \
176 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
177 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
178 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
179 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
180 {OFFSET (OBJ[N].Size), 1, INT_V}
182 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
183 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
184 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
185 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
186 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
187 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
188 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
189 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
190 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
191 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
192 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
193 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
194 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
195 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
196 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
197 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
199 {OFFSET (OAMPriorityRotation), 1, INT_V},
200 {OFFSET (OAMAddr), 2, INT_V},
201 {OFFSET (OAMFlip), 1, INT_V},
202 {OFFSET (OAMTileAddress), 2, INT_V},
203 {OFFSET (IRQVBeamPos), 2, INT_V},
204 {OFFSET (IRQHBeamPos), 2, INT_V},
205 {OFFSET (VBeamPosLatched), 2, INT_V},
206 {OFFSET (HBeamPosLatched), 2, INT_V},
207 {OFFSET (HBeamFlip), 1, INT_V},
208 {OFFSET (VBeamFlip), 1, INT_V},
209 {OFFSET (HVBeamCounterLatched), 1, INT_V},
210 {OFFSET (MatrixA), 2, INT_V},
211 {OFFSET (MatrixB), 2, INT_V},
212 {OFFSET (MatrixC), 2, INT_V},
213 {OFFSET (MatrixD), 2, INT_V},
214 {OFFSET (CentreX), 2, INT_V},
215 {OFFSET (CentreY), 2, INT_V},
216 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
217 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
218 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
219 {OFFSET (CGADD), 1, INT_V},
220 {OFFSET (FixedColourRed), 1, INT_V},
221 {OFFSET (FixedColourGreen), 1, INT_V},
222 {OFFSET (FixedColourBlue), 1, INT_V},
223 {OFFSET (SavedOAMAddr), 2, INT_V},
224 {OFFSET (ScreenHeight), 2, INT_V},
225 {OFFSET (WRAM), 4, INT_V},
226 {OFFSET (ForcedBlanking), 1, INT_V},
227 {OFFSET (OBJNameSelect), 2, INT_V},
228 {OFFSET (OBJSizeSelect), 1, INT_V},
229 {OFFSET (OBJNameBase), 2, INT_V},
230 {OFFSET (OAMReadFlip), 1, INT_V},
231 {OFFSET (VTimerEnabled), 1, INT_V},
232 {OFFSET (HTimerEnabled), 1, INT_V},
233 {OFFSET (HTimerPosition), 2, INT_V},
234 {OFFSET (Mosaic), 1, INT_V},
235 {OFFSET (Mode7HFlip), 1, INT_V},
236 {OFFSET (Mode7VFlip), 1, INT_V},
237 {OFFSET (Mode7Repeat), 1, INT_V},
238 {OFFSET (Window1Left), 1, INT_V},
239 {OFFSET (Window1Right), 1, INT_V},
240 {OFFSET (Window2Left), 1, INT_V},
241 {OFFSET (Window2Right), 1, INT_V},
243 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
244 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
245 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
246 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
247 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
249 O(0), O(1), O(2), O(3), O(4), O(5),
253 {OFFSET (CGFLIPRead), 1, INT_V},
254 {OFFSET (Need16x8Mulitply), 1, INT_V},
255 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
256 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
257 {OFFSET (Need16x8Mulitply), 1, INT_V},
258 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
262 #define OFFSET(f) Offset(f,struct SDMA *)
264 static FreezeData SnapDMA [] = {
266 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
267 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
268 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
269 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
270 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
271 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
272 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
273 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
274 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
275 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
276 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
277 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
278 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
279 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
280 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
282 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
287 #define OFFSET(f) Offset(f,struct SAPU *)
289 static FreezeData SnapAPU [] = {
290 {OFFSET (Cycles), 4, INT_V},
291 {OFFSET (ShowROM), 1, INT_V},
292 {OFFSET (Flags), 1, INT_V},
293 {OFFSET (KeyedChannels), 1, INT_V},
294 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
295 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
296 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
297 {OFFSET (Timer), 3, uint16_ARRAY_V},
298 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
299 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
300 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
304 #define OFFSET(f) Offset(f,struct SAPURegisters *)
306 static FreezeData SnapAPURegisters [] = {
307 {OFFSET (P) , 1, INT_V},
308 {OFFSET (YA.W), 2, INT_V},
309 {OFFSET (X) , 1, INT_V},
310 {OFFSET (S) , 1, INT_V},
311 {OFFSET (PC) , 2, INT_V}
316 #define OFFSET(f) Offset(f,SSoundData *)
318 static FreezeData SnapSoundData [] = {
319 {OFFSET (master_volume_left), 2, INT_V},
320 {OFFSET (master_volume_right), 2, INT_V},
321 {OFFSET (echo_volume_left), 2, INT_V},
322 {OFFSET (echo_volume_right), 2, INT_V},
323 {OFFSET (echo_enable), 4, INT_V},
324 {OFFSET (echo_feedback), 4, INT_V},
325 {OFFSET (echo_ptr), 4, INT_V},
326 {OFFSET (echo_buffer_size), 4, INT_V},
327 {OFFSET (echo_write_enabled), 4, INT_V},
328 {OFFSET (echo_channel_enable), 4, INT_V},
329 {OFFSET (pitch_mod), 4, INT_V},
330 {OFFSET (dummy), 3, uint32_ARRAY_V},
332 {OFFSET (channels [N].state), 4, INT_V}, \
333 {OFFSET (channels [N].type), 4, INT_V}, \
334 {OFFSET (channels [N].volume_left), 2, INT_V}, \
335 {OFFSET (channels [N].volume_right), 2, INT_V}, \
336 {OFFSET (channels [N].hertz), 4, INT_V}, \
337 {OFFSET (channels [N].count), 4, INT_V}, \
338 {OFFSET (channels [N].loop), 1, INT_V}, \
339 {OFFSET (channels [N].envx), 4, INT_V}, \
340 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
341 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
342 {OFFSET (channels [N].envx_target), 2, INT_V}, \
343 {OFFSET (channels [N].env_error), 4, INT_V}, \
344 {OFFSET (channels [N].erate), 4, INT_V}, \
345 {OFFSET (channels [N].direction), 4, INT_V}, \
346 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
347 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
348 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
349 {OFFSET (channels [N].release_rate), 4, INT_V}, \
350 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
351 {OFFSET (channels [N].sample), 2, INT_V}, \
352 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
353 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
354 {OFFSET (channels [N].sample_number), 2, INT_V}, \
355 {OFFSET (channels [N].last_block), 1, INT_V}, \
356 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
357 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
358 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
359 {OFFSET (channels [N].mode), 4, INT_V}
361 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
368 #define OFFSET(f) Offset(f,struct SSA1Registers *)
370 static FreezeData SnapSA1Registers [] = {
371 {OFFSET (PB), 1, INT_V},
372 {OFFSET (DB), 1, INT_V},
373 {OFFSET (P.W), 2, INT_V},
374 {OFFSET (A.W), 2, INT_V},
375 {OFFSET (D.W), 2, INT_V},
376 {OFFSET (S.W), 2, INT_V},
377 {OFFSET (X.W), 2, INT_V},
378 {OFFSET (Y.W), 2, INT_V},
379 {OFFSET (PC), 2, INT_V}
383 #define OFFSET(f) Offset(f,struct SSA1 *)
385 static FreezeData SnapSA1 [] = {
386 {OFFSET (Flags), 4, INT_V},
387 {OFFSET (NMIActive), 1, INT_V},
388 {OFFSET (IRQActive), 1, INT_V},
389 {OFFSET (WaitingForInterrupt), 1, INT_V},
390 {OFFSET (op1), 2, INT_V},
391 {OFFSET (op2), 2, INT_V},
392 {OFFSET (arithmetic_op), 4, INT_V},
393 {OFFSET (sum), 8, INT_V},
394 {OFFSET (overflow), 1, INT_V}
400 static void Freeze ();
401 static int Unfreeze ();
402 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
404 static void FreezeBlock (const char *name, uint8 *block, int size);
406 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
408 static int UnfreezeBlock (const char *name, uint8 *block, int size);
410 bool8 S9xFreezeGame (const char *filename)
412 if ((ss_st = OPEN_STREAM(filename, "wb")))
422 bool8 S9xUnfreezeGame (const char *filename)
424 if ((ss_st = OPEN_STREAM(filename, "rb")))
427 if ((result = Unfreeze()) != SUCCESS)
432 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
433 "File not in Snes9x freeze format");
437 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
438 "Incompatable Snes9x freeze file format version");
442 // should never happen
456 static void Freeze ()
461 S9xSetSoundMute (TRUE);
463 if (Settings.SuperFX)
464 S9xSuperFXPreSaveState ();
467 S9xSRTCPreSaveState ();
469 for (i = 0; i < 8; i++)
471 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
472 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
474 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
475 WRITE_STREAM(buffer, strlen(buffer), ss_st);
476 sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
477 Memory.ROMFilename, 0);
478 WRITE_STREAM(buffer, strlen(buffer) + 1, ss_st);
479 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
480 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
481 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
482 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
485 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
486 FreezeBlock ("RAM", Memory.RAM, 0x20000);
487 FreezeBlock ("SRA", ::SRAM, 0x20000);
488 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
489 if (Settings.APUEnabled)
492 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
493 // copy all SPC700 regs to savestate compatible struct
494 SAPURegisters spcregs;
496 spcregs.YA.W = IAPU.YA.W;
499 spcregs.PC = IAPU.PC - IAPU.RAM;
500 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
501 COUNT (SnapAPURegisters));
503 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
504 FreezeStruct ("SOU", &SoundData, SnapSoundData,
505 COUNT (SnapSoundData));
510 SA1Registers.PC = SA1.PC - SA1.PCBase;
512 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
513 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
514 COUNT (SnapSA1Registers));
517 S9xSetSoundMute (FALSE);
519 if (Settings.SuperFX)
520 S9xSuperFXPostSaveState ();
524 static int Unfreeze()
527 char rom_filename[1024];
531 int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
532 if (READ_STREAM(buffer, len, ss_st) != len)
534 printf("%s: Failed to read header\n", __func__);
537 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
539 printf("%s: Read header not correct\n", __func__);
542 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
544 printf("%s: Wrong version\n", __func__);
545 return WRONG_VERSION;
548 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
550 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
554 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
555 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
557 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
558 "Current loaded ROM image doesn't match that required by freeze-game file.");
562 uint32 old_flags = CPU.Flags;
564 uint32 sa1_old_flags = SA1.Flags;
567 S9xSetSoundMute (TRUE);
569 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
570 COUNT (SnapCPU))) != SUCCESS)
574 Memory.FixROMSpeed ();
575 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
576 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
577 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
579 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
583 IPPU.ColorsChanged = TRUE;
584 IPPU.OBJChanged = TRUE;
586 S9xFixColourBrightness ();
587 IPPU.RenderThisFrame = FALSE;
589 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
590 COUNT (SnapDMA))) != SUCCESS)
593 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
596 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
599 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
602 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
606 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
608 SAPURegisters spcregs;
609 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
610 COUNT (SnapAPURegisters))) != SUCCESS)
612 // reload all SPC700 regs from savestate compatible struct
614 IAPU.YA.W = spcregs.YA.W;
617 IAPU.PC = IAPU.RAM + spcregs.PC;
619 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
622 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
623 COUNT (SnapSoundData))) != SUCCESS)
626 // notaz: just to be sure
627 for(int u=0; u<8; u++) {
628 SoundData.channels[u].env_ind_attack &= 0xf;
629 SoundData.channels[u].env_ind_decay &= 0x7;
630 SoundData.channels[u].env_ind_sustain&= 0x1f;
633 S9xSetSoundMute (FALSE);
634 S9xAPUUnpackStatus ();
635 if (APUCheckDirectPage ())
636 IAPU.DirectPage = IAPU.RAM + 0x100;
638 IAPU.DirectPage = IAPU.RAM;
639 Settings.APUEnabled = TRUE;
640 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
644 Settings.APUEnabled = FALSE;
645 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
646 S9xSetSoundMute (TRUE);
649 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
650 COUNT(SnapSA1))) == SUCCESS)
652 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
653 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
656 S9xFixSA1AfterSnapshotLoad ();
657 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
660 S9xFixSoundAfterSnapshotLoad ();
661 ICPU.ShiftedPB = Registers.PB << 16;
662 ICPU.ShiftedDB = Registers.DB << 16;
663 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
665 #if !CONF_BUILD_ASM_CPU
672 if (Settings.SuperFX)
673 S9xSuperFXPostLoadState ();
676 S9xSRTCPostLoadState ();
677 if (Settings.SDD1) S9xSDD1PostLoadState ();
682 int FreezeSize (int size, int type)
695 void FreezeStruct(const char *name, void *base, FreezeData *fields,
698 // Work out the size of the required block
703 for (i = 0; i < num_fields; i++)
705 if (fields [i].offset + FreezeSize (fields [i].size,
706 fields [i].type) > len)
707 len = fields [i].offset + FreezeSize (fields [i].size,
711 // uint8 *block = new uint8 [len];
712 uint8 *block = (uint8*)malloc(len);
718 // Build the block ready to be streamed out
719 for (i = 0; i < num_fields; i++)
721 switch (fields [i].type)
724 switch (fields [i].size)
727 *ptr++ = *((uint8 *) base + fields [i].offset);
730 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
731 *ptr++ = (uint8) (word >> 8);
732 *ptr++ = (uint8) word;
735 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
736 *ptr++ = (uint8) (dword >> 24);
737 *ptr++ = (uint8) (dword >> 16);
738 *ptr++ = (uint8) (dword >> 8);
739 *ptr++ = (uint8) dword;
742 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
743 *ptr++ = (uint8) (qword >> 56);
744 *ptr++ = (uint8) (qword >> 48);
745 *ptr++ = (uint8) (qword >> 40);
746 *ptr++ = (uint8) (qword >> 32);
747 *ptr++ = (uint8) (qword >> 24);
748 *ptr++ = (uint8) (qword >> 16);
749 *ptr++ = (uint8) (qword >> 8);
750 *ptr++ = (uint8) qword;
755 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
756 ptr += fields [i].size;
759 for (j = 0; j < fields [i].size; j++)
761 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
762 *ptr++ = (uint8) (word >> 8);
763 *ptr++ = (uint8) word;
767 for (j = 0; j < fields [i].size; j++)
769 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
770 *ptr++ = (uint8) (dword >> 24);
771 *ptr++ = (uint8) (dword >> 16);
772 *ptr++ = (uint8) (dword >> 8);
773 *ptr++ = (uint8) dword;
779 FreezeBlock (name, block, len);
784 void FreezeBlock (const char *name, uint8 *block, int size)
787 sprintf (buffer, "%s:%06d:", name, size);
788 WRITE_STREAM(buffer, strlen(buffer), ss_st);
789 WRITE_STREAM(block, size, ss_st);
792 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
795 // Work out the size of the required block
800 for (i = 0; i < num_fields; i++)
802 if (fields [i].offset + FreezeSize (fields [i].size,
803 fields [i].type) > len)
804 len = fields [i].offset + FreezeSize (fields [i].size,
808 uint8 *block = (uint8*)malloc(len);
815 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
821 // Unpack the block of data into a C structure
822 for (i = 0; i < num_fields; i++)
824 switch (fields [i].type)
827 switch (fields [i].size)
830 *((uint8 *) base + fields [i].offset) = *ptr++;
835 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
838 dword = *ptr++ << 24;
839 dword |= *ptr++ << 16;
840 dword |= *ptr++ << 8;
842 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
845 qword = (int64) *ptr++ << 56;
846 qword |= (int64) *ptr++ << 48;
847 qword |= (int64) *ptr++ << 40;
848 qword |= (int64) *ptr++ << 32;
849 qword |= (int64) *ptr++ << 24;
850 qword |= (int64) *ptr++ << 16;
851 qword |= (int64) *ptr++ << 8;
852 qword |= (int64) *ptr++;
853 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
858 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
859 ptr += fields [i].size;
862 for (j = 0; j < fields [i].size; j++)
866 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
870 for (j = 0; j < fields [i].size; j++)
872 dword = *ptr++ << 24;
873 dword |= *ptr++ << 16;
874 dword |= *ptr++ << 8;
876 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
887 int UnfreezeBlock(const char *name, uint8 *block, int size)
893 if (READ_STREAM(buffer, 11, ss_st) != 11 ||
894 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
895 (len = atoi (&buffer [4])) == 0)
897 dprintf("%s: %s: Invalid block header\n", __func__, name);
907 if (READ_STREAM(block, len, ss_st) != len)
909 dprintf("%s: Invalid block\n", __func__);
915 char *junk = (char*)malloc(rem);
916 READ_STREAM(junk, rem, ss_st);