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>
66 #define dprintf(...) /* disabled */
72 void S9xSuperFXPreSaveState ();
73 void S9xSuperFXPostSaveState ();
74 void S9xSuperFXPostLoadState ();
75 //bool8 S9xUnfreezeZSNES (const char *filename);
86 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
89 #define Offset(field,structure) \
90 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
92 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
95 #define OFFSET(f) Offset(f,struct SCPUState *)
97 static FreezeData SnapCPU [] = {
98 {OFFSET (Flags), 4, INT_V},
99 {OFFSET (BranchSkip), 1, INT_V},
100 {OFFSET (NMIActive), 1, INT_V},
101 {OFFSET (IRQActive), 1, INT_V},
102 {OFFSET (WaitingForInterrupt), 1, INT_V},
103 {OFFSET (WhichEvent), 1, INT_V},
104 {OFFSET (Cycles), 4, INT_V},
105 {OFFSET (NextEvent), 4, INT_V},
106 {OFFSET (V_Counter), 4, INT_V},
107 {OFFSET (MemSpeed), 4, INT_V},
108 {OFFSET (MemSpeedx2), 4, INT_V},
109 {OFFSET (FastROMSpeed), 4, INT_V}
113 #define OFFSET(f) Offset(f,struct SRegisters *)
115 static FreezeData SnapRegisters [] = {
116 {OFFSET (PB), 1, INT_V},
117 {OFFSET (DB), 1, INT_V},
118 {OFFSET (P.W), 2, INT_V},
119 {OFFSET (A.W), 2, INT_V},
120 {OFFSET (D.W), 2, INT_V},
121 {OFFSET (S.W), 2, INT_V},
122 {OFFSET (X.W), 2, INT_V},
123 {OFFSET (Y.W), 2, INT_V},
124 {OFFSET (PC), 2, INT_V}
128 #define OFFSET(f) Offset(f,struct SPPU *)
130 static FreezeData SnapPPU [] = {
131 {OFFSET (BGMode), 1, INT_V},
132 {OFFSET (BG3Priority), 1, INT_V},
133 {OFFSET (Brightness), 1, INT_V},
134 {OFFSET (VMA.High), 1, INT_V},
135 {OFFSET (VMA.Increment), 1, INT_V},
136 {OFFSET (VMA.Address), 2, INT_V},
137 {OFFSET (VMA.Mask1), 2, INT_V},
138 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
139 {OFFSET (VMA.Shift), 2, INT_V},
140 {OFFSET (BG[0].SCBase), 2, INT_V},
141 {OFFSET (BG[0].VOffset), 2, INT_V},
142 {OFFSET (BG[0].HOffset), 2, INT_V},
143 {OFFSET (BG[0].BGSize), 1, INT_V},
144 {OFFSET (BG[0].NameBase), 2, INT_V},
145 {OFFSET (BG[0].SCSize), 2, INT_V},
147 {OFFSET (BG[1].SCBase), 2, INT_V},
148 {OFFSET (BG[1].VOffset), 2, INT_V},
149 {OFFSET (BG[1].HOffset), 2, INT_V},
150 {OFFSET (BG[1].BGSize), 1, INT_V},
151 {OFFSET (BG[1].NameBase), 2, INT_V},
152 {OFFSET (BG[1].SCSize), 2, INT_V},
154 {OFFSET (BG[2].SCBase), 2, INT_V},
155 {OFFSET (BG[2].VOffset), 2, INT_V},
156 {OFFSET (BG[2].HOffset), 2, INT_V},
157 {OFFSET (BG[2].BGSize), 1, INT_V},
158 {OFFSET (BG[2].NameBase), 2, INT_V},
159 {OFFSET (BG[2].SCSize), 2, INT_V},
161 {OFFSET (BG[3].SCBase), 2, INT_V},
162 {OFFSET (BG[3].VOffset), 2, INT_V},
163 {OFFSET (BG[3].HOffset), 2, INT_V},
164 {OFFSET (BG[3].BGSize), 1, INT_V},
165 {OFFSET (BG[3].NameBase), 2, INT_V},
166 {OFFSET (BG[3].SCSize), 2, INT_V},
168 {OFFSET (CGFLIP), 1, INT_V},
169 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
170 {OFFSET (FirstSprite), 1, INT_V},
172 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
173 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
174 {OFFSET (OBJ[N].Name), 2, INT_V}, \
175 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
176 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
177 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
178 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
179 {OFFSET (OBJ[N].Size), 1, INT_V}
181 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
182 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
183 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
184 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
185 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
186 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
187 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
188 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
189 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
190 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
191 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
192 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
193 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
194 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
195 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
196 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
198 {OFFSET (OAMPriorityRotation), 1, INT_V},
199 {OFFSET (OAMAddr), 2, INT_V},
200 {OFFSET (OAMFlip), 1, INT_V},
201 {OFFSET (OAMTileAddress), 2, INT_V},
202 {OFFSET (IRQVBeamPos), 2, INT_V},
203 {OFFSET (IRQHBeamPos), 2, INT_V},
204 {OFFSET (VBeamPosLatched), 2, INT_V},
205 {OFFSET (HBeamPosLatched), 2, INT_V},
206 {OFFSET (HBeamFlip), 1, INT_V},
207 {OFFSET (VBeamFlip), 1, INT_V},
208 {OFFSET (HVBeamCounterLatched), 1, INT_V},
209 {OFFSET (MatrixA), 2, INT_V},
210 {OFFSET (MatrixB), 2, INT_V},
211 {OFFSET (MatrixC), 2, INT_V},
212 {OFFSET (MatrixD), 2, INT_V},
213 {OFFSET (CentreX), 2, INT_V},
214 {OFFSET (CentreY), 2, INT_V},
215 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
216 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
217 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
218 {OFFSET (CGADD), 1, INT_V},
219 {OFFSET (FixedColourRed), 1, INT_V},
220 {OFFSET (FixedColourGreen), 1, INT_V},
221 {OFFSET (FixedColourBlue), 1, INT_V},
222 {OFFSET (SavedOAMAddr), 2, INT_V},
223 {OFFSET (ScreenHeight), 2, INT_V},
224 {OFFSET (WRAM), 4, INT_V},
225 {OFFSET (ForcedBlanking), 1, INT_V},
226 {OFFSET (OBJNameSelect), 2, INT_V},
227 {OFFSET (OBJSizeSelect), 1, INT_V},
228 {OFFSET (OBJNameBase), 2, INT_V},
229 {OFFSET (OAMReadFlip), 1, INT_V},
230 {OFFSET (VTimerEnabled), 1, INT_V},
231 {OFFSET (HTimerEnabled), 1, INT_V},
232 {OFFSET (HTimerPosition), 2, INT_V},
233 {OFFSET (Mosaic), 1, INT_V},
234 {OFFSET (Mode7HFlip), 1, INT_V},
235 {OFFSET (Mode7VFlip), 1, INT_V},
236 {OFFSET (Mode7Repeat), 1, INT_V},
237 {OFFSET (Window1Left), 1, INT_V},
238 {OFFSET (Window1Right), 1, INT_V},
239 {OFFSET (Window2Left), 1, INT_V},
240 {OFFSET (Window2Right), 1, INT_V},
242 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
243 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
244 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
245 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
246 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
248 O(0), O(1), O(2), O(3), O(4), O(5),
252 {OFFSET (CGFLIPRead), 1, INT_V},
253 {OFFSET (Need16x8Mulitply), 1, INT_V},
254 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
255 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
256 {OFFSET (Need16x8Mulitply), 1, INT_V},
257 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
261 #define OFFSET(f) Offset(f,struct SDMA *)
263 static FreezeData SnapDMA [] = {
265 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
266 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
267 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
268 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
269 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
270 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
271 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
272 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
273 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
274 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
275 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
276 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
277 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
278 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
279 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
281 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
286 #define OFFSET(f) Offset(f,struct SAPU *)
288 static FreezeData SnapAPU [] = {
289 {OFFSET (Cycles), 4, INT_V},
290 {OFFSET (ShowROM), 1, INT_V},
291 {OFFSET (Flags), 1, INT_V},
292 {OFFSET (KeyedChannels), 1, INT_V},
293 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
294 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
295 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
296 {OFFSET (Timer), 3, uint16_ARRAY_V},
297 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
298 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
299 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
303 #define OFFSET(f) Offset(f,struct SAPURegisters *)
305 static FreezeData SnapAPURegisters [] = {
306 {OFFSET (P) , 1, INT_V},
307 {OFFSET (YA.W), 2, INT_V},
308 {OFFSET (X) , 1, INT_V},
309 {OFFSET (S) , 1, INT_V},
310 {OFFSET (PC) , 2, INT_V}
315 #define OFFSET(f) Offset(f,SSoundData *)
317 static FreezeData SnapSoundData [] = {
318 {OFFSET (master_volume_left), 2, INT_V},
319 {OFFSET (master_volume_right), 2, INT_V},
320 {OFFSET (echo_volume_left), 2, INT_V},
321 {OFFSET (echo_volume_right), 2, INT_V},
322 {OFFSET (echo_enable), 4, INT_V},
323 {OFFSET (echo_feedback), 4, INT_V},
324 {OFFSET (echo_ptr), 4, INT_V},
325 {OFFSET (echo_buffer_size), 4, INT_V},
326 {OFFSET (echo_write_enabled), 4, INT_V},
327 {OFFSET (echo_channel_enable), 4, INT_V},
328 {OFFSET (pitch_mod), 4, INT_V},
329 {OFFSET (dummy), 3, uint32_ARRAY_V},
331 {OFFSET (channels [N].state), 4, INT_V}, \
332 {OFFSET (channels [N].type), 4, INT_V}, \
333 {OFFSET (channels [N].volume_left), 2, INT_V}, \
334 {OFFSET (channels [N].volume_right), 2, INT_V}, \
335 {OFFSET (channels [N].hertz), 4, INT_V}, \
336 {OFFSET (channels [N].count), 4, INT_V}, \
337 {OFFSET (channels [N].loop), 1, INT_V}, \
338 {OFFSET (channels [N].envx), 4, INT_V}, \
339 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
340 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
341 {OFFSET (channels [N].envx_target), 2, INT_V}, \
342 {OFFSET (channels [N].env_error), 4, INT_V}, \
343 {OFFSET (channels [N].erate), 4, INT_V}, \
344 {OFFSET (channels [N].direction), 4, INT_V}, \
345 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
346 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
347 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
348 {OFFSET (channels [N].release_rate), 4, INT_V}, \
349 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
350 {OFFSET (channels [N].sample), 2, INT_V}, \
351 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
352 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
353 {OFFSET (channels [N].sample_number), 2, INT_V}, \
354 {OFFSET (channels [N].last_block), 1, INT_V}, \
355 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
356 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
357 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
358 {OFFSET (channels [N].mode), 4, INT_V}
360 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
367 #define OFFSET(f) Offset(f,struct SSA1Registers *)
369 static FreezeData SnapSA1Registers [] = {
370 {OFFSET (PB), 1, INT_V},
371 {OFFSET (DB), 1, INT_V},
372 {OFFSET (P.W), 2, INT_V},
373 {OFFSET (A.W), 2, INT_V},
374 {OFFSET (D.W), 2, INT_V},
375 {OFFSET (S.W), 2, INT_V},
376 {OFFSET (X.W), 2, INT_V},
377 {OFFSET (Y.W), 2, INT_V},
378 {OFFSET (PC), 2, INT_V}
382 #define OFFSET(f) Offset(f,struct SSA1 *)
384 static FreezeData SnapSA1 [] = {
385 {OFFSET (Flags), 4, INT_V},
386 {OFFSET (NMIActive), 1, INT_V},
387 {OFFSET (IRQActive), 1, INT_V},
388 {OFFSET (WaitingForInterrupt), 1, INT_V},
389 {OFFSET (op1), 2, INT_V},
390 {OFFSET (op2), 2, INT_V},
391 {OFFSET (arithmetic_op), 4, INT_V},
392 {OFFSET (sum), 8, INT_V},
393 {OFFSET (overflow), 1, INT_V}
399 static void Freeze ();
400 static int Unfreeze ();
401 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
403 static void FreezeBlock (const char *name, uint8 *block, int size);
405 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
407 static int UnfreezeBlock (const char *name, uint8 *block, int size);
409 bool8 S9xFreezeGame (const char *filename)
411 if ((ss_st = OPEN_STREAM(filename, "wb")))
421 bool8 S9xUnfreezeGame (const char *filename)
423 if ((ss_st = OPEN_STREAM(filename, "rb")))
426 if ((result = Unfreeze()) != SUCCESS)
431 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
432 "File not in Snes9x freeze format");
436 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
437 "Incompatable Snes9x freeze file format version");
441 // should never happen
455 static void Freeze ()
460 S9xSetSoundMute (TRUE);
462 if (Settings.SuperFX)
463 S9xSuperFXPreSaveState ();
466 S9xSRTCPreSaveState ();
468 for (i = 0; i < 8; i++)
470 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
471 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
473 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
474 WRITE_STREAM(buffer, strlen(buffer), ss_st);
475 sprintf (buffer, "NAM:%06zu:%s%c", strlen(Memory.ROMFilename) + 1,
476 Memory.ROMFilename, 0);
477 WRITE_STREAM(buffer, strlen(buffer) + 1, ss_st);
478 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
479 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
480 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
481 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
484 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
485 FreezeBlock ("RAM", Memory.RAM, 0x20000);
486 FreezeBlock ("SRA", ::SRAM, 0x20000);
487 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
488 if (Settings.APUEnabled)
491 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
492 // copy all SPC700 regs to savestate compatible struct
493 SAPURegisters spcregs;
495 spcregs.YA.W = IAPU.YA.W;
498 spcregs.PC = IAPU.PC - IAPU.RAM;
499 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
500 COUNT (SnapAPURegisters));
502 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
503 FreezeStruct ("SOU", &SoundData, SnapSoundData,
504 COUNT (SnapSoundData));
509 SA1Registers.PC = SA1.PC - SA1.PCBase;
511 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
512 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
513 COUNT (SnapSA1Registers));
516 S9xSetSoundMute (FALSE);
518 if (Settings.SuperFX)
519 S9xSuperFXPostSaveState ();
523 static int Unfreeze()
526 char rom_filename[1024];
530 int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
531 if (READ_STREAM(buffer, len, ss_st) != len)
533 printf("%s: Failed to read header\n", __func__);
536 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
538 printf("%s: Read header not correct\n", __func__);
541 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
543 printf("%s: Wrong version\n", __func__);
544 return WRONG_VERSION;
547 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
549 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
553 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
554 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
556 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
557 "Current loaded ROM image doesn't match that required by freeze-game file.");
561 uint32 old_flags = CPU.Flags;
563 uint32 sa1_old_flags = SA1.Flags;
566 S9xSetSoundMute (TRUE);
568 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
569 COUNT (SnapCPU))) != SUCCESS)
573 Memory.FixROMSpeed ();
574 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
575 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
576 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
578 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
582 IPPU.ColorsChanged = TRUE;
583 IPPU.OBJChanged = TRUE;
585 S9xFixColourBrightness ();
586 IPPU.RenderThisFrame = FALSE;
588 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
589 COUNT (SnapDMA))) != SUCCESS)
592 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
595 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
598 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
601 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
605 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
607 SAPURegisters spcregs;
608 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
609 COUNT (SnapAPURegisters))) != SUCCESS)
611 // reload all SPC700 regs from savestate compatible struct
613 IAPU.YA.W = spcregs.YA.W;
616 IAPU.PC = IAPU.RAM + spcregs.PC;
618 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
621 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
622 COUNT (SnapSoundData))) != SUCCESS)
625 // notaz: just to be sure
626 for(int u=0; u<8; u++) {
627 SoundData.channels[u].env_ind_attack &= 0xf;
628 SoundData.channels[u].env_ind_decay &= 0x7;
629 SoundData.channels[u].env_ind_sustain&= 0x1f;
632 S9xSetSoundMute (FALSE);
633 S9xAPUUnpackStatus ();
634 if (APUCheckDirectPage ())
635 IAPU.DirectPage = IAPU.RAM + 0x100;
637 IAPU.DirectPage = IAPU.RAM;
638 Settings.APUEnabled = TRUE;
639 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
643 Settings.APUEnabled = FALSE;
644 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
645 S9xSetSoundMute (TRUE);
648 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
649 COUNT(SnapSA1))) == SUCCESS)
651 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
652 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
655 S9xFixSA1AfterSnapshotLoad ();
656 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
659 S9xFixSoundAfterSnapshotLoad ();
660 ICPU.ShiftedPB = Registers.PB << 16;
661 ICPU.ShiftedDB = Registers.DB << 16;
662 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
664 #if !CONF_BUILD_ASM_CPU
671 if (Settings.SuperFX)
672 S9xSuperFXPostLoadState ();
675 S9xSRTCPostLoadState ();
676 if (Settings.SDD1) S9xSDD1PostLoadState ();
681 int FreezeSize (int size, int type)
694 void FreezeStruct(const char *name, void *base, FreezeData *fields,
697 // Work out the size of the required block
702 for (i = 0; i < num_fields; i++)
704 if (fields [i].offset + FreezeSize (fields [i].size,
705 fields [i].type) > len)
706 len = fields [i].offset + FreezeSize (fields [i].size,
710 // uint8 *block = new uint8 [len];
711 uint8 *block = (uint8*)malloc(len);
717 // Build the block ready to be streamed out
718 for (i = 0; i < num_fields; i++)
720 switch (fields [i].type)
723 switch (fields [i].size)
726 *ptr++ = *((uint8 *) base + fields [i].offset);
729 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
730 *ptr++ = (uint8) (word >> 8);
731 *ptr++ = (uint8) word;
734 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
735 *ptr++ = (uint8) (dword >> 24);
736 *ptr++ = (uint8) (dword >> 16);
737 *ptr++ = (uint8) (dword >> 8);
738 *ptr++ = (uint8) dword;
741 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
742 *ptr++ = (uint8) (qword >> 56);
743 *ptr++ = (uint8) (qword >> 48);
744 *ptr++ = (uint8) (qword >> 40);
745 *ptr++ = (uint8) (qword >> 32);
746 *ptr++ = (uint8) (qword >> 24);
747 *ptr++ = (uint8) (qword >> 16);
748 *ptr++ = (uint8) (qword >> 8);
749 *ptr++ = (uint8) qword;
754 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
755 ptr += fields [i].size;
758 for (j = 0; j < fields [i].size; j++)
760 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
761 *ptr++ = (uint8) (word >> 8);
762 *ptr++ = (uint8) word;
766 for (j = 0; j < fields [i].size; j++)
768 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
769 *ptr++ = (uint8) (dword >> 24);
770 *ptr++ = (uint8) (dword >> 16);
771 *ptr++ = (uint8) (dword >> 8);
772 *ptr++ = (uint8) dword;
778 FreezeBlock (name, block, len);
783 void FreezeBlock (const char *name, uint8 *block, int size)
786 sprintf (buffer, "%s:%06d:", name, size);
787 WRITE_STREAM(buffer, strlen(buffer), ss_st);
788 WRITE_STREAM(block, size, ss_st);
791 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
794 // Work out the size of the required block
799 for (i = 0; i < num_fields; i++)
801 if (fields [i].offset + FreezeSize (fields [i].size,
802 fields [i].type) > len)
803 len = fields [i].offset + FreezeSize (fields [i].size,
807 uint8 *block = (uint8*)malloc(len);
814 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
820 // Unpack the block of data into a C structure
821 for (i = 0; i < num_fields; i++)
823 switch (fields [i].type)
826 switch (fields [i].size)
829 *((uint8 *) base + fields [i].offset) = *ptr++;
834 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
837 dword = *ptr++ << 24;
838 dword |= *ptr++ << 16;
839 dword |= *ptr++ << 8;
841 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
844 qword = (int64) *ptr++ << 56;
845 qword |= (int64) *ptr++ << 48;
846 qword |= (int64) *ptr++ << 40;
847 qword |= (int64) *ptr++ << 32;
848 qword |= (int64) *ptr++ << 24;
849 qword |= (int64) *ptr++ << 16;
850 qword |= (int64) *ptr++ << 8;
851 qword |= (int64) *ptr++;
852 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
857 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
858 ptr += fields [i].size;
861 for (j = 0; j < fields [i].size; j++)
865 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
869 for (j = 0; j < fields [i].size; j++)
871 dword = *ptr++ << 24;
872 dword |= *ptr++ << 16;
873 dword |= *ptr++ << 8;
875 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
886 int UnfreezeBlock(const char *name, uint8 *block, int size)
892 if (READ_STREAM(buffer, 11, ss_st) != 11 ||
893 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
894 (len = atoi (&buffer [4])) == 0)
896 dprintf("%s: %s: Invalid block header\n", __func__, name);
906 if (READ_STREAM(block, len, ss_st) != len)
908 dprintf("%s: Invalid block\n", __func__);
914 char *junk = (char*)malloc(rem);
915 READ_STREAM(junk, rem, ss_st);