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.
47 #if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)
49 #include <sys/types.h>
54 //#include "snaporig.h"
70 // notaz: file i/o function pointers for states,
71 // changing funcs will allow to enable/disable gzipped saves
72 extern int (*statef_open)(const char *fname, const char *mode);
73 extern int (*statef_read)(void *p, int l);
74 extern int (*statef_write)(void *p, int l);
75 extern void (*statef_close)();
81 void S9xSuperFXPreSaveState ();
82 void S9xSuperFXPostSaveState ();
83 void S9xSuperFXPostLoadState ();
87 //bool8 S9xUnfreezeZSNES (const char *filename);
96 INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
99 #define Offset(field,structure) \
100 ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
102 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
105 #define OFFSET(f) Offset(f,struct SCPUState *)
107 static FreezeData SnapCPU [] = {
108 {OFFSET (Flags), 4, INT_V},
109 {OFFSET (BranchSkip), 1, INT_V},
110 {OFFSET (NMIActive), 1, INT_V},
111 {OFFSET (IRQActive), 1, INT_V},
112 {OFFSET (WaitingForInterrupt), 1, INT_V},
113 {OFFSET (WhichEvent), 1, INT_V},
114 {OFFSET (Cycles), 4, INT_V},
115 {OFFSET (NextEvent), 4, INT_V},
116 {OFFSET (V_Counter), 4, INT_V},
117 {OFFSET (MemSpeed), 4, INT_V},
118 {OFFSET (MemSpeedx2), 4, INT_V},
119 {OFFSET (FastROMSpeed), 4, INT_V}
123 #define OFFSET(f) Offset(f,struct SRegisters *)
125 static FreezeData SnapRegisters [] = {
126 {OFFSET (PB), 1, INT_V},
127 {OFFSET (DB), 1, INT_V},
128 {OFFSET (P.W), 2, INT_V},
129 {OFFSET (A.W), 2, INT_V},
130 {OFFSET (D.W), 2, INT_V},
131 {OFFSET (S.W), 2, INT_V},
132 {OFFSET (X.W), 2, INT_V},
133 {OFFSET (Y.W), 2, INT_V},
134 {OFFSET (PC), 2, INT_V}
138 #define OFFSET(f) Offset(f,struct SPPU *)
140 static FreezeData SnapPPU [] = {
141 {OFFSET (BGMode), 1, INT_V},
142 {OFFSET (BG3Priority), 1, INT_V},
143 {OFFSET (Brightness), 1, INT_V},
144 {OFFSET (VMA.High), 1, INT_V},
145 {OFFSET (VMA.Increment), 1, INT_V},
146 {OFFSET (VMA.Address), 2, INT_V},
147 {OFFSET (VMA.Mask1), 2, INT_V},
148 {OFFSET (VMA.FullGraphicCount), 2, INT_V},
149 {OFFSET (VMA.Shift), 2, INT_V},
150 {OFFSET (BG[0].SCBase), 2, INT_V},
151 {OFFSET (BG[0].VOffset), 2, INT_V},
152 {OFFSET (BG[0].HOffset), 2, INT_V},
153 {OFFSET (BG[0].BGSize), 1, INT_V},
154 {OFFSET (BG[0].NameBase), 2, INT_V},
155 {OFFSET (BG[0].SCSize), 2, INT_V},
157 {OFFSET (BG[1].SCBase), 2, INT_V},
158 {OFFSET (BG[1].VOffset), 2, INT_V},
159 {OFFSET (BG[1].HOffset), 2, INT_V},
160 {OFFSET (BG[1].BGSize), 1, INT_V},
161 {OFFSET (BG[1].NameBase), 2, INT_V},
162 {OFFSET (BG[1].SCSize), 2, INT_V},
164 {OFFSET (BG[2].SCBase), 2, INT_V},
165 {OFFSET (BG[2].VOffset), 2, INT_V},
166 {OFFSET (BG[2].HOffset), 2, INT_V},
167 {OFFSET (BG[2].BGSize), 1, INT_V},
168 {OFFSET (BG[2].NameBase), 2, INT_V},
169 {OFFSET (BG[2].SCSize), 2, INT_V},
171 {OFFSET (BG[3].SCBase), 2, INT_V},
172 {OFFSET (BG[3].VOffset), 2, INT_V},
173 {OFFSET (BG[3].HOffset), 2, INT_V},
174 {OFFSET (BG[3].BGSize), 1, INT_V},
175 {OFFSET (BG[3].NameBase), 2, INT_V},
176 {OFFSET (BG[3].SCSize), 2, INT_V},
178 {OFFSET (CGFLIP), 1, INT_V},
179 {OFFSET (CGDATA), 256, uint16_ARRAY_V},
180 {OFFSET (FirstSprite), 1, INT_V},
182 {OFFSET (OBJ[N].HPos), 2, INT_V}, \
183 {OFFSET (OBJ[N].VPos), 2, INT_V}, \
184 {OFFSET (OBJ[N].Name), 2, INT_V}, \
185 {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
186 {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
187 {OFFSET (OBJ[N].Priority), 1, INT_V}, \
188 {OFFSET (OBJ[N].Palette), 1, INT_V}, \
189 {OFFSET (OBJ[N].Size), 1, INT_V}
191 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
192 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
193 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
194 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
195 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
196 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
197 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
198 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
199 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
200 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
201 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
202 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
203 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
204 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
205 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
206 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
208 {OFFSET (OAMPriorityRotation), 1, INT_V},
209 {OFFSET (OAMAddr), 2, INT_V},
210 {OFFSET (OAMFlip), 1, INT_V},
211 {OFFSET (OAMTileAddress), 2, INT_V},
212 {OFFSET (IRQVBeamPos), 2, INT_V},
213 {OFFSET (IRQHBeamPos), 2, INT_V},
214 {OFFSET (VBeamPosLatched), 2, INT_V},
215 {OFFSET (HBeamPosLatched), 2, INT_V},
216 {OFFSET (HBeamFlip), 1, INT_V},
217 {OFFSET (VBeamFlip), 1, INT_V},
218 {OFFSET (HVBeamCounterLatched), 1, INT_V},
219 {OFFSET (MatrixA), 2, INT_V},
220 {OFFSET (MatrixB), 2, INT_V},
221 {OFFSET (MatrixC), 2, INT_V},
222 {OFFSET (MatrixD), 2, INT_V},
223 {OFFSET (CentreX), 2, INT_V},
224 {OFFSET (CentreY), 2, INT_V},
225 {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
226 {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
227 {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
228 {OFFSET (CGADD), 1, INT_V},
229 {OFFSET (FixedColourRed), 1, INT_V},
230 {OFFSET (FixedColourGreen), 1, INT_V},
231 {OFFSET (FixedColourBlue), 1, INT_V},
232 {OFFSET (SavedOAMAddr), 2, INT_V},
233 {OFFSET (ScreenHeight), 2, INT_V},
234 {OFFSET (WRAM), 4, INT_V},
235 {OFFSET (ForcedBlanking), 1, INT_V},
236 {OFFSET (OBJNameSelect), 2, INT_V},
237 {OFFSET (OBJSizeSelect), 1, INT_V},
238 {OFFSET (OBJNameBase), 2, INT_V},
239 {OFFSET (OAMReadFlip), 1, INT_V},
240 {OFFSET (VTimerEnabled), 1, INT_V},
241 {OFFSET (HTimerEnabled), 1, INT_V},
242 {OFFSET (HTimerPosition), 2, INT_V},
243 {OFFSET (Mosaic), 1, INT_V},
244 {OFFSET (Mode7HFlip), 1, INT_V},
245 {OFFSET (Mode7VFlip), 1, INT_V},
246 {OFFSET (Mode7Repeat), 1, INT_V},
247 {OFFSET (Window1Left), 1, INT_V},
248 {OFFSET (Window1Right), 1, INT_V},
249 {OFFSET (Window2Left), 1, INT_V},
250 {OFFSET (Window2Right), 1, INT_V},
252 {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
253 {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
254 {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
255 {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
256 {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
258 O(0), O(1), O(2), O(3), O(4), O(5),
262 {OFFSET (CGFLIPRead), 1, INT_V},
263 {OFFSET (Need16x8Mulitply), 1, INT_V},
264 {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
265 {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
266 {OFFSET (Need16x8Mulitply), 1, INT_V},
267 {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
271 #define OFFSET(f) Offset(f,struct SDMA *)
273 static FreezeData SnapDMA [] = {
275 {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
276 {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
277 {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
278 {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
279 {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
280 {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
281 {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
282 {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
283 {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
284 {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
285 {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
286 {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
287 {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
288 {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
289 {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
291 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
296 #define OFFSET(f) Offset(f,struct SAPU *)
298 static FreezeData SnapAPU [] = {
299 {OFFSET (Cycles), 4, INT_V},
300 {OFFSET (ShowROM), 1, INT_V},
301 {OFFSET (Flags), 1, INT_V},
302 {OFFSET (KeyedChannels), 1, INT_V},
303 {OFFSET (OutPorts), 4, uint8_ARRAY_V},
304 {OFFSET (DSP), 0x80, uint8_ARRAY_V},
305 {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
306 {OFFSET (Timer), 3, uint16_ARRAY_V},
307 {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
308 {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
309 {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
313 #define OFFSET(f) Offset(f,struct SAPURegisters *)
315 static FreezeData SnapAPURegisters [] = {
316 {OFFSET (P) , 1, INT_V},
317 {OFFSET (YA.W), 2, INT_V},
318 {OFFSET (X) , 1, INT_V},
319 {OFFSET (S) , 1, INT_V},
320 {OFFSET (PC) , 2, INT_V}
325 #define OFFSET(f) Offset(f,SSoundData *)
327 static FreezeData SnapSoundData [] = {
328 {OFFSET (master_volume_left), 2, INT_V},
329 {OFFSET (master_volume_right), 2, INT_V},
330 {OFFSET (echo_volume_left), 2, INT_V},
331 {OFFSET (echo_volume_right), 2, INT_V},
332 {OFFSET (echo_enable), 4, INT_V},
333 {OFFSET (echo_feedback), 4, INT_V},
334 {OFFSET (echo_ptr), 4, INT_V},
335 {OFFSET (echo_buffer_size), 4, INT_V},
336 {OFFSET (echo_write_enabled), 4, INT_V},
337 {OFFSET (echo_channel_enable), 4, INT_V},
338 {OFFSET (pitch_mod), 4, INT_V},
339 {OFFSET (dummy), 3, uint32_ARRAY_V},
341 {OFFSET (channels [N].state), 4, INT_V}, \
342 {OFFSET (channels [N].type), 4, INT_V}, \
343 {OFFSET (channels [N].volume_left), 2, INT_V}, \
344 {OFFSET (channels [N].volume_right), 2, INT_V}, \
345 {OFFSET (channels [N].hertz), 4, INT_V}, \
346 {OFFSET (channels [N].count), 4, INT_V}, \
347 {OFFSET (channels [N].loop), 1, INT_V}, \
348 {OFFSET (channels [N].envx), 4, INT_V}, \
349 {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
350 {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
351 {OFFSET (channels [N].envx_target), 2, INT_V}, \
352 {OFFSET (channels [N].env_error), 4, INT_V}, \
353 {OFFSET (channels [N].erate), 4, INT_V}, \
354 {OFFSET (channels [N].direction), 4, INT_V}, \
355 {OFFSET (channels [N].attack_rate), 4, INT_V}, \
356 {OFFSET (channels [N].decay_rate), 4, INT_V}, \
357 {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
358 {OFFSET (channels [N].release_rate), 4, INT_V}, \
359 {OFFSET (channels [N].sustain_level), 4, INT_V}, \
360 {OFFSET (channels [N].sample), 2, INT_V}, \
361 {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
362 {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
363 {OFFSET (channels [N].sample_number), 2, INT_V}, \
364 {OFFSET (channels [N].last_block), 1, INT_V}, \
365 {OFFSET (channels [N].needs_decode), 1, INT_V}, \
366 {OFFSET (channels [N].block_pointer), 4, INT_V}, \
367 {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
368 {OFFSET (channels [N].mode), 4, INT_V}
370 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
377 #define OFFSET(f) Offset(f,struct SSA1Registers *)
379 static FreezeData SnapSA1Registers [] = {
380 {OFFSET (PB), 1, INT_V},
381 {OFFSET (DB), 1, INT_V},
382 {OFFSET (P.W), 2, INT_V},
383 {OFFSET (A.W), 2, INT_V},
384 {OFFSET (D.W), 2, INT_V},
385 {OFFSET (S.W), 2, INT_V},
386 {OFFSET (X.W), 2, INT_V},
387 {OFFSET (Y.W), 2, INT_V},
388 {OFFSET (PC), 2, INT_V}
392 #define OFFSET(f) Offset(f,struct SSA1 *)
394 static FreezeData SnapSA1 [] = {
395 {OFFSET (Flags), 4, INT_V},
396 {OFFSET (NMIActive), 1, INT_V},
397 {OFFSET (IRQActive), 1, INT_V},
398 {OFFSET (WaitingForInterrupt), 1, INT_V},
399 {OFFSET (op1), 2, INT_V},
400 {OFFSET (op2), 2, INT_V},
401 {OFFSET (arithmetic_op), 4, INT_V},
402 {OFFSET (sum), 8, INT_V},
403 {OFFSET (overflow), 1, INT_V}
407 //static char ROMFilename [_MAX_PATH];
408 //static char SnapshotFilename [_MAX_PATH];
410 static void Freeze ();
411 static int Unfreeze ();
412 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
414 static void FreezeBlock (const char *name, uint8 *block, int size);
416 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
418 static int UnfreezeBlock (const char *name, uint8 *block, int size);
420 bool8 Snapshot (const char *filename)
422 return (S9xFreezeGame (filename));
425 bool8 S9xFreezeGame (const char *filename)
427 if(statef_open(filename, "wb"))
437 bool8 S9xUnfreezeGame (const char *filename)
439 if(statef_open(filename, "rb"))
442 if ((result = Unfreeze()) != SUCCESS)
447 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
448 "File not in Snes9x freeze format");
452 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
453 "Incompatable Snes9x freeze file format version");
457 // should never happen
471 static void Freeze ()
476 S9xSetSoundMute (TRUE);
478 if (Settings.SuperFX)
479 S9xSuperFXPreSaveState ();
482 S9xSRTCPreSaveState ();
484 for (i = 0; i < 8; i++)
486 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
487 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
489 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
490 statef_write(buffer, strlen (buffer));
491 sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
492 Memory.ROMFilename, 0);
493 statef_write(buffer, strlen (buffer) + 1);
494 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
495 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
496 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
497 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
500 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
501 FreezeBlock ("RAM", Memory.RAM, 0x20000);
502 FreezeBlock ("SRA", ::SRAM, 0x20000);
503 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
504 if (Settings.APUEnabled)
507 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
508 // copy all SPC700 regs to savestate compatible struct
509 SAPURegisters spcregs;
511 spcregs.YA.W = IAPU.YA.W;
514 spcregs.PC = IAPU.PC - IAPU.RAM;
515 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
516 COUNT (SnapAPURegisters));
518 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
519 FreezeStruct ("SOU", &SoundData, SnapSoundData,
520 COUNT (SnapSoundData));
525 SA1Registers.PC = SA1.PC - SA1.PCBase;
527 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
528 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
529 COUNT (SnapSA1Registers));
532 S9xSetSoundMute (FALSE);
534 if (Settings.SuperFX)
535 S9xSuperFXPostSaveState ();
539 static int Unfreeze()
541 // notaz: overflowing the damn Symbian stack again
543 char rom_filename [512];
547 unsigned int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
548 if (statef_read(buffer, len) != (int)len)
550 printf("failed to read header\r\n");
551 return (WRONG_FORMAT);
553 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
555 printf("read header not correct\r\n");
556 return (WRONG_FORMAT);
558 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
560 printf("Wrong version\r\n");
561 return (WRONG_VERSION);
564 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 512)) != SUCCESS)
566 printf("UnfreezeBlock NAM failed\r\n");
570 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
571 strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0)
573 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
574 "Current loaded ROM image doesn't match that required by freeze-game file.");
575 printf("filename mismatch\r\n");
580 uint32 old_flags = CPU.Flags;
582 uint32 sa1_old_flags = SA1.Flags;
585 S9xSetSoundMute (TRUE);
587 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
588 COUNT (SnapCPU))) != SUCCESS)
592 Memory.FixROMSpeed ();
593 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
594 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
595 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
597 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
601 IPPU.ColorsChanged = TRUE;
602 IPPU.OBJChanged = TRUE;
604 S9xFixColourBrightness ();
605 IPPU.RenderThisFrame = FALSE;
607 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
608 COUNT (SnapDMA))) != SUCCESS)
611 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
614 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
617 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
620 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
624 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
626 SAPURegisters spcregs;
627 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
628 COUNT (SnapAPURegisters))) != SUCCESS)
630 // reload all SPC700 regs from savestate compatible struct
632 IAPU.YA.W = spcregs.YA.W;
635 IAPU.PC = IAPU.RAM + spcregs.PC;
637 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
640 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
641 COUNT (SnapSoundData))) != SUCCESS)
644 // notaz: just to be sure
645 for(int u=0; u<8; u++) {
646 SoundData.channels[u].env_ind_attack &= 0xf;
647 SoundData.channels[u].env_ind_decay &= 0x7;
648 SoundData.channels[u].env_ind_sustain&= 0x1f;
651 S9xSetSoundMute (FALSE);
652 S9xAPUUnpackStatus ();
653 if (APUCheckDirectPage ())
654 IAPU.DirectPage = IAPU.RAM + 0x100;
656 IAPU.DirectPage = IAPU.RAM;
657 Settings.APUEnabled = TRUE;
658 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
662 Settings.APUEnabled = FALSE;
663 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
664 S9xSetSoundMute (TRUE);
667 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
668 COUNT(SnapSA1))) == SUCCESS)
670 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
671 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
674 S9xFixSA1AfterSnapshotLoad ();
675 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
678 S9xFixSoundAfterSnapshotLoad ();
679 ICPU.ShiftedPB = Registers.PB << 16;
680 ICPU.ShiftedDB = Registers.DB << 16;
681 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
684 //S9xUnpackStatus (); // not needed
685 //S9xFixCycles (); // also not needed?
688 if (Settings.SuperFX)
689 S9xSuperFXPostLoadState ();
692 S9xSRTCPostLoadState ();
693 if (Settings.SDD1) S9xSDD1PostLoadState ();
698 int FreezeSize (int size, int type)
711 void FreezeStruct(const char *name, void *base, FreezeData *fields,
714 // Work out the size of the required block
719 for (i = 0; i < num_fields; i++)
721 if (fields [i].offset + FreezeSize (fields [i].size,
722 fields [i].type) > len)
723 len = fields [i].offset + FreezeSize (fields [i].size,
727 // uint8 *block = new uint8 [len];
728 uint8 *block = (uint8*)malloc(len);
734 // Build the block ready to be streamed out
735 for (i = 0; i < num_fields; i++)
737 switch (fields [i].type)
740 switch (fields [i].size)
743 *ptr++ = *((uint8 *) base + fields [i].offset);
746 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
747 *ptr++ = (uint8) (word >> 8);
748 *ptr++ = (uint8) word;
751 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
752 *ptr++ = (uint8) (dword >> 24);
753 *ptr++ = (uint8) (dword >> 16);
754 *ptr++ = (uint8) (dword >> 8);
755 *ptr++ = (uint8) dword;
758 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
759 *ptr++ = (uint8) (qword >> 56);
760 *ptr++ = (uint8) (qword >> 48);
761 *ptr++ = (uint8) (qword >> 40);
762 *ptr++ = (uint8) (qword >> 32);
763 *ptr++ = (uint8) (qword >> 24);
764 *ptr++ = (uint8) (qword >> 16);
765 *ptr++ = (uint8) (qword >> 8);
766 *ptr++ = (uint8) qword;
771 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
772 ptr += fields [i].size;
775 for (j = 0; j < fields [i].size; j++)
777 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
778 *ptr++ = (uint8) (word >> 8);
779 *ptr++ = (uint8) word;
783 for (j = 0; j < fields [i].size; j++)
785 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
786 *ptr++ = (uint8) (dword >> 24);
787 *ptr++ = (uint8) (dword >> 16);
788 *ptr++ = (uint8) (dword >> 8);
789 *ptr++ = (uint8) dword;
795 FreezeBlock (name, block, len);
800 void FreezeBlock (const char *name, uint8 *block, int size)
803 sprintf (buffer, "%s:%06d:", name, size);
804 statef_write(buffer, strlen (buffer));
805 statef_write(block, size);
808 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
811 // Work out the size of the required block
816 for (i = 0; i < num_fields; i++)
818 if (fields [i].offset + FreezeSize (fields [i].size,
819 fields [i].type) > len)
820 len = fields [i].offset + FreezeSize (fields [i].size,
824 uint8 *block = (uint8*)malloc(len);
831 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
837 // Unpack the block of data into a C structure
838 for (i = 0; i < num_fields; i++)
840 switch (fields [i].type)
843 switch (fields [i].size)
846 *((uint8 *) base + fields [i].offset) = *ptr++;
851 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
854 dword = *ptr++ << 24;
855 dword |= *ptr++ << 16;
856 dword |= *ptr++ << 8;
858 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
861 qword = (int64) *ptr++ << 56;
862 qword |= (int64) *ptr++ << 48;
863 qword |= (int64) *ptr++ << 40;
864 qword |= (int64) *ptr++ << 32;
865 qword |= (int64) *ptr++ << 24;
866 qword |= (int64) *ptr++ << 16;
867 qword |= (int64) *ptr++ << 8;
868 qword |= (int64) *ptr++;
869 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
874 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
875 ptr += fields [i].size;
878 for (j = 0; j < fields [i].size; j++)
882 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
886 for (j = 0; j < fields [i].size; j++)
888 dword = *ptr++ << 24;
889 dword |= *ptr++ << 16;
890 dword |= *ptr++ << 8;
892 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
903 int UnfreezeBlock(const char *name, uint8 *block, int size)
908 printf("UnfreezeBlock: %s\r\n",name);
909 if (statef_read(buffer, 11) != 11 ||
910 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
911 (len = atoi (&buffer [4])) == 0)
913 printf("UnfreezeBlock err1\n");
914 return (WRONG_FORMAT);
923 if (statef_read(block, len) != len)
925 printf("UnfreezeBlock err2\n");
926 return (WRONG_FORMAT);
931 char *junk = (char*)malloc(rem);
932 statef_read(junk, rem);