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 S9xFreezeGame (const char *filename)
422 if(statef_open(filename, "wb"))
432 bool8 S9xUnfreezeGame (const char *filename)
434 if(statef_open(filename, "rb"))
437 if ((result = Unfreeze()) != SUCCESS)
442 S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT,
443 "File not in Snes9x freeze format");
447 S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
448 "Incompatable Snes9x freeze file format version");
452 // should never happen
466 static void Freeze ()
471 S9xSetSoundMute (TRUE);
473 if (Settings.SuperFX)
474 S9xSuperFXPreSaveState ();
477 S9xSRTCPreSaveState ();
479 for (i = 0; i < 8; i++)
481 SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
482 SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
484 sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
485 statef_write(buffer, strlen (buffer));
486 sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
487 Memory.ROMFilename, 0);
488 statef_write(buffer, strlen (buffer) + 1);
489 FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
490 FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
491 FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
492 FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
495 FreezeBlock ("VRA", Memory.VRAM, 0x10000);
496 FreezeBlock ("RAM", Memory.RAM, 0x20000);
497 FreezeBlock ("SRA", ::SRAM, 0x20000);
498 FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
499 if (Settings.APUEnabled)
502 FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
503 // copy all SPC700 regs to savestate compatible struct
504 SAPURegisters spcregs;
506 spcregs.YA.W = IAPU.YA.W;
509 spcregs.PC = IAPU.PC - IAPU.RAM;
510 FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
511 COUNT (SnapAPURegisters));
513 FreezeBlock ("ARA", IAPU.RAM, 0x10000);
514 FreezeStruct ("SOU", &SoundData, SnapSoundData,
515 COUNT (SnapSoundData));
520 SA1Registers.PC = SA1.PC - SA1.PCBase;
522 FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
523 FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers,
524 COUNT (SnapSA1Registers));
527 S9xSetSoundMute (FALSE);
529 if (Settings.SuperFX)
530 S9xSuperFXPostSaveState ();
534 static int Unfreeze()
536 // notaz: overflowing the damn Symbian stack again
538 char rom_filename [512];
542 unsigned int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
543 if (statef_read(buffer, len) != (int)len)
545 printf("failed to read header\r\n");
546 return (WRONG_FORMAT);
548 if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
550 printf("read header not correct\r\n");
551 return (WRONG_FORMAT);
553 if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
555 printf("Wrong version\r\n");
556 return (WRONG_VERSION);
559 if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 512)) != SUCCESS)
561 printf("UnfreezeBlock NAM failed\r\n");
565 if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
566 strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
568 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
569 "Current loaded ROM image doesn't match that required by freeze-game file.");
570 printf("filename mismatch\r\n");
575 uint32 old_flags = CPU.Flags;
577 uint32 sa1_old_flags = SA1.Flags;
580 S9xSetSoundMute (TRUE);
582 if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU,
583 COUNT (SnapCPU))) != SUCCESS)
587 Memory.FixROMSpeed ();
588 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
589 SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
590 if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
592 if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
596 IPPU.ColorsChanged = TRUE;
597 IPPU.OBJChanged = TRUE;
599 S9xFixColourBrightness ();
600 IPPU.RenderThisFrame = FALSE;
602 if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA,
603 COUNT (SnapDMA))) != SUCCESS)
606 if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
609 if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
612 if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
615 if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
619 if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
621 SAPURegisters spcregs;
622 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
623 COUNT (SnapAPURegisters))) != SUCCESS)
625 // reload all SPC700 regs from savestate compatible struct
627 IAPU.YA.W = spcregs.YA.W;
630 IAPU.PC = IAPU.RAM + spcregs.PC;
632 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
635 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
636 COUNT (SnapSoundData))) != SUCCESS)
639 // notaz: just to be sure
640 for(int u=0; u<8; u++) {
641 SoundData.channels[u].env_ind_attack &= 0xf;
642 SoundData.channels[u].env_ind_decay &= 0x7;
643 SoundData.channels[u].env_ind_sustain&= 0x1f;
646 S9xSetSoundMute (FALSE);
647 S9xAPUUnpackStatus ();
648 if (APUCheckDirectPage ())
649 IAPU.DirectPage = IAPU.RAM + 0x100;
651 IAPU.DirectPage = IAPU.RAM;
652 Settings.APUEnabled = TRUE;
653 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
657 Settings.APUEnabled = FALSE;
658 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
659 S9xSetSoundMute (TRUE);
662 if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1,
663 COUNT(SnapSA1))) == SUCCESS)
665 if ((result = UnfreezeStruct ("SAR", &SA1Registers,
666 SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
669 S9xFixSA1AfterSnapshotLoad ();
670 SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
673 S9xFixSoundAfterSnapshotLoad ();
674 ICPU.ShiftedPB = Registers.PB << 16;
675 ICPU.ShiftedDB = Registers.DB << 16;
676 S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
679 //S9xUnpackStatus (); // not needed
680 //S9xFixCycles (); // also not needed?
683 if (Settings.SuperFX)
684 S9xSuperFXPostLoadState ();
687 S9xSRTCPostLoadState ();
688 if (Settings.SDD1) S9xSDD1PostLoadState ();
693 int FreezeSize (int size, int type)
706 void FreezeStruct(const char *name, void *base, FreezeData *fields,
709 // Work out the size of the required block
714 for (i = 0; i < num_fields; i++)
716 if (fields [i].offset + FreezeSize (fields [i].size,
717 fields [i].type) > len)
718 len = fields [i].offset + FreezeSize (fields [i].size,
722 // uint8 *block = new uint8 [len];
723 uint8 *block = (uint8*)malloc(len);
729 // Build the block ready to be streamed out
730 for (i = 0; i < num_fields; i++)
732 switch (fields [i].type)
735 switch (fields [i].size)
738 *ptr++ = *((uint8 *) base + fields [i].offset);
741 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
742 *ptr++ = (uint8) (word >> 8);
743 *ptr++ = (uint8) word;
746 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
747 *ptr++ = (uint8) (dword >> 24);
748 *ptr++ = (uint8) (dword >> 16);
749 *ptr++ = (uint8) (dword >> 8);
750 *ptr++ = (uint8) dword;
753 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
754 *ptr++ = (uint8) (qword >> 56);
755 *ptr++ = (uint8) (qword >> 48);
756 *ptr++ = (uint8) (qword >> 40);
757 *ptr++ = (uint8) (qword >> 32);
758 *ptr++ = (uint8) (qword >> 24);
759 *ptr++ = (uint8) (qword >> 16);
760 *ptr++ = (uint8) (qword >> 8);
761 *ptr++ = (uint8) qword;
766 memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
767 ptr += fields [i].size;
770 for (j = 0; j < fields [i].size; j++)
772 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
773 *ptr++ = (uint8) (word >> 8);
774 *ptr++ = (uint8) word;
778 for (j = 0; j < fields [i].size; j++)
780 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
781 *ptr++ = (uint8) (dword >> 24);
782 *ptr++ = (uint8) (dword >> 16);
783 *ptr++ = (uint8) (dword >> 8);
784 *ptr++ = (uint8) dword;
790 FreezeBlock (name, block, len);
795 void FreezeBlock (const char *name, uint8 *block, int size)
798 sprintf (buffer, "%s:%06d:", name, size);
799 statef_write(buffer, strlen (buffer));
800 statef_write(block, size);
803 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
806 // Work out the size of the required block
811 for (i = 0; i < num_fields; i++)
813 if (fields [i].offset + FreezeSize (fields [i].size,
814 fields [i].type) > len)
815 len = fields [i].offset + FreezeSize (fields [i].size,
819 uint8 *block = (uint8*)malloc(len);
826 if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
832 // Unpack the block of data into a C structure
833 for (i = 0; i < num_fields; i++)
835 switch (fields [i].type)
838 switch (fields [i].size)
841 *((uint8 *) base + fields [i].offset) = *ptr++;
846 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
849 dword = *ptr++ << 24;
850 dword |= *ptr++ << 16;
851 dword |= *ptr++ << 8;
853 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
856 qword = (int64) *ptr++ << 56;
857 qword |= (int64) *ptr++ << 48;
858 qword |= (int64) *ptr++ << 40;
859 qword |= (int64) *ptr++ << 32;
860 qword |= (int64) *ptr++ << 24;
861 qword |= (int64) *ptr++ << 16;
862 qword |= (int64) *ptr++ << 8;
863 qword |= (int64) *ptr++;
864 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
869 memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
870 ptr += fields [i].size;
873 for (j = 0; j < fields [i].size; j++)
877 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
881 for (j = 0; j < fields [i].size; j++)
883 dword = *ptr++ << 24;
884 dword |= *ptr++ << 16;
885 dword |= *ptr++ << 8;
887 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
898 int UnfreezeBlock(const char *name, uint8 *block, int size)
903 printf("UnfreezeBlock: %s\r\n",name);
904 if (statef_read(buffer, 11) != 11 ||
905 strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
906 (len = atoi (&buffer [4])) == 0)
908 printf("UnfreezeBlock err1\n");
909 return (WRONG_FORMAT);
918 if (statef_read(block, len) != len)
920 printf("UnfreezeBlock err2\n");
921 return (WRONG_FORMAT);
926 char *junk = (char*)malloc(rem);
927 statef_read(junk, rem);