fix compiler warnings
[drnoksnes] / snapshot.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
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).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
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.
25  *
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.
29  *
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.
33  *
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
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41
42 #include <string.h>
43 #include <ctype.h>
44 #include <stdlib.h>
45
46 #if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)
47 #include <unistd.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #endif
51
52 #include "snapshot.h"
53 #include "memmap.h"
54 #include "snes9x.h"
55 #include "65c816.h"
56 #include "ppu.h"
57 #include "cpuexec.h"
58 #include "display.h"
59 #include "apu.h"
60 #include "soundux.h"
61 #ifdef USE_SA1
62 #include "sa1.h"
63 #endif
64 #include "srtc.h"
65 #include "sdd1.h"
66
67 extern uint8 *SRAM;
68
69 #ifdef ZSNES_FX
70 START_EXTERN_C
71 void S9xSuperFXPreSaveState ();
72 void S9xSuperFXPostSaveState ();
73 void S9xSuperFXPostLoadState ();
74 //bool8 S9xUnfreezeZSNES (const char *filename);
75 END_EXTERN_C
76 #endif
77
78 typedef struct {
79     int offset;
80     int size;
81     int type;
82 } FreezeData;
83
84 enum {
85     INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V
86 };
87
88 #define Offset(field,structure) \
89         ((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL)))
90
91 #define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
92
93 #undef OFFSET
94 #define OFFSET(f) Offset(f,struct SCPUState *)
95
96 static FreezeData SnapCPU [] = {
97     {OFFSET (Flags), 4, INT_V},
98     {OFFSET (BranchSkip), 1, INT_V},
99     {OFFSET (NMIActive), 1, INT_V},
100     {OFFSET (IRQActive), 1, INT_V},
101     {OFFSET (WaitingForInterrupt), 1, INT_V},
102     {OFFSET (WhichEvent), 1, INT_V},
103     {OFFSET (Cycles), 4, INT_V},
104     {OFFSET (NextEvent), 4, INT_V},
105     {OFFSET (V_Counter), 4, INT_V},
106     {OFFSET (MemSpeed), 4, INT_V},
107     {OFFSET (MemSpeedx2), 4, INT_V},
108     {OFFSET (FastROMSpeed), 4, INT_V}
109 };
110
111 #undef OFFSET
112 #define OFFSET(f) Offset(f,struct SRegisters *)
113
114 static FreezeData SnapRegisters [] = {
115     {OFFSET (PB),  1, INT_V},
116     {OFFSET (DB),  1, INT_V},
117     {OFFSET (P.W), 2, INT_V},
118     {OFFSET (A.W), 2, INT_V},
119     {OFFSET (D.W), 2, INT_V},
120     {OFFSET (S.W), 2, INT_V},
121     {OFFSET (X.W), 2, INT_V},
122     {OFFSET (Y.W), 2, INT_V},
123     {OFFSET (PC),  2, INT_V}
124 };
125
126 #undef OFFSET
127 #define OFFSET(f) Offset(f,struct SPPU *)
128
129 static FreezeData SnapPPU [] = {
130     {OFFSET (BGMode), 1, INT_V},
131     {OFFSET (BG3Priority), 1, INT_V},
132     {OFFSET (Brightness), 1, INT_V},
133     {OFFSET (VMA.High), 1, INT_V},
134     {OFFSET (VMA.Increment), 1, INT_V},
135     {OFFSET (VMA.Address), 2, INT_V},
136     {OFFSET (VMA.Mask1), 2, INT_V},
137     {OFFSET (VMA.FullGraphicCount), 2, INT_V},
138     {OFFSET (VMA.Shift), 2, INT_V},
139     {OFFSET (BG[0].SCBase), 2, INT_V},
140     {OFFSET (BG[0].VOffset), 2, INT_V},
141     {OFFSET (BG[0].HOffset), 2, INT_V},
142     {OFFSET (BG[0].BGSize), 1, INT_V},
143     {OFFSET (BG[0].NameBase), 2, INT_V},
144     {OFFSET (BG[0].SCSize), 2, INT_V},
145
146     {OFFSET (BG[1].SCBase), 2, INT_V},
147     {OFFSET (BG[1].VOffset), 2, INT_V},
148     {OFFSET (BG[1].HOffset), 2, INT_V},
149     {OFFSET (BG[1].BGSize), 1, INT_V},
150     {OFFSET (BG[1].NameBase), 2, INT_V},
151     {OFFSET (BG[1].SCSize), 2, INT_V},
152
153     {OFFSET (BG[2].SCBase), 2, INT_V},
154     {OFFSET (BG[2].VOffset), 2, INT_V},
155     {OFFSET (BG[2].HOffset), 2, INT_V},
156     {OFFSET (BG[2].BGSize), 1, INT_V},
157     {OFFSET (BG[2].NameBase), 2, INT_V},
158     {OFFSET (BG[2].SCSize), 2, INT_V},
159
160     {OFFSET (BG[3].SCBase), 2, INT_V},
161     {OFFSET (BG[3].VOffset), 2, INT_V},
162     {OFFSET (BG[3].HOffset), 2, INT_V},
163     {OFFSET (BG[3].BGSize), 1, INT_V},
164     {OFFSET (BG[3].NameBase), 2, INT_V},
165     {OFFSET (BG[3].SCSize), 2, INT_V},
166
167     {OFFSET (CGFLIP), 1, INT_V},
168     {OFFSET (CGDATA), 256, uint16_ARRAY_V},
169     {OFFSET (FirstSprite), 1, INT_V},
170 #define O(N) \
171     {OFFSET (OBJ[N].HPos), 2, INT_V}, \
172     {OFFSET (OBJ[N].VPos), 2, INT_V}, \
173     {OFFSET (OBJ[N].Name), 2, INT_V}, \
174     {OFFSET (OBJ[N].VFlip), 1, INT_V}, \
175     {OFFSET (OBJ[N].HFlip), 1, INT_V}, \
176     {OFFSET (OBJ[N].Priority), 1, INT_V}, \
177     {OFFSET (OBJ[N].Palette), 1, INT_V}, \
178     {OFFSET (OBJ[N].Size), 1, INT_V}
179
180     O(  0), O(  1), O(  2), O(  3), O(  4), O(  5), O(  6), O(  7),
181     O(  8), O(  9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
182     O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
183     O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
184     O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
185     O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
186     O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
187     O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
188     O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
189     O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
190     O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
191     O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
192     O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
193     O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
194     O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
195     O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
196 #undef O
197     {OFFSET (OAMPriorityRotation), 1, INT_V},
198     {OFFSET (OAMAddr), 2, INT_V},
199     {OFFSET (OAMFlip), 1, INT_V},
200     {OFFSET (OAMTileAddress), 2, INT_V},
201     {OFFSET (IRQVBeamPos), 2, INT_V},
202     {OFFSET (IRQHBeamPos), 2, INT_V},
203     {OFFSET (VBeamPosLatched), 2, INT_V},
204     {OFFSET (HBeamPosLatched), 2, INT_V},
205     {OFFSET (HBeamFlip), 1, INT_V},
206     {OFFSET (VBeamFlip), 1, INT_V},
207     {OFFSET (HVBeamCounterLatched), 1, INT_V},
208     {OFFSET (MatrixA), 2, INT_V},
209     {OFFSET (MatrixB), 2, INT_V},
210     {OFFSET (MatrixC), 2, INT_V},
211     {OFFSET (MatrixD), 2, INT_V},
212     {OFFSET (CentreX), 2, INT_V},
213     {OFFSET (CentreY), 2, INT_V},
214     {OFFSET (Joypad1ButtonReadPos), 1, INT_V},
215     {OFFSET (Joypad2ButtonReadPos), 1, INT_V},
216     {OFFSET (Joypad3ButtonReadPos), 1, INT_V},
217     {OFFSET (CGADD), 1, INT_V},
218     {OFFSET (FixedColourRed), 1, INT_V},
219     {OFFSET (FixedColourGreen), 1, INT_V},
220     {OFFSET (FixedColourBlue), 1, INT_V},
221     {OFFSET (SavedOAMAddr), 2, INT_V},
222     {OFFSET (ScreenHeight), 2, INT_V},
223     {OFFSET (WRAM), 4, INT_V},
224     {OFFSET (ForcedBlanking), 1, INT_V},
225     {OFFSET (OBJNameSelect), 2, INT_V},
226     {OFFSET (OBJSizeSelect), 1, INT_V},
227     {OFFSET (OBJNameBase), 2, INT_V},
228     {OFFSET (OAMReadFlip), 1, INT_V},
229     {OFFSET (VTimerEnabled), 1, INT_V},
230     {OFFSET (HTimerEnabled), 1, INT_V},
231     {OFFSET (HTimerPosition), 2, INT_V},
232     {OFFSET (Mosaic), 1, INT_V},
233     {OFFSET (Mode7HFlip), 1, INT_V},
234     {OFFSET (Mode7VFlip), 1, INT_V},
235     {OFFSET (Mode7Repeat), 1, INT_V},
236     {OFFSET (Window1Left), 1, INT_V},
237     {OFFSET (Window1Right), 1, INT_V},
238     {OFFSET (Window2Left), 1, INT_V},
239     {OFFSET (Window2Right), 1, INT_V},
240 #define O(N) \
241     {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V}, \
242     {OFFSET (ClipWindow1Enable[N]), 1, INT_V}, \
243     {OFFSET (ClipWindow2Enable[N]), 1, INT_V}, \
244     {OFFSET (ClipWindow1Inside[N]), 1, INT_V}, \
245     {OFFSET (ClipWindow2Inside[N]), 1, INT_V}
246
247     O(0), O(1), O(2), O(3), O(4), O(5),
248
249 #undef O
250
251     {OFFSET (CGFLIPRead), 1, INT_V},
252     {OFFSET (Need16x8Mulitply), 1, INT_V},
253     {OFFSET (BGMosaic), 4, uint8_ARRAY_V},
254     {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V},
255     {OFFSET (Need16x8Mulitply), 1, INT_V},
256     {OFFSET (MouseSpeed), 2, uint8_ARRAY_V}
257 };
258
259 #undef OFFSET
260 #define OFFSET(f) Offset(f,struct SDMA *)
261
262 static FreezeData SnapDMA [] = {
263 #define O(N) \
264     {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V}, \
265     {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V}, \
266     {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V}, \
267     {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V}, \
268     {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V}, \
269     {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
270     {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V}, \
271     {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V}, \
272     {OFFSET (TransferBytes) + N * sizeof (struct SDMA), 2, INT_V}, \
273     {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V}, \
274     {OFFSET (IndirectAddress) + N * sizeof (struct SDMA), 2, INT_V}, \
275     {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V}, \
276     {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V}, \
277     {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V}, \
278     {OFFSET (FirstLine) + N * sizeof (struct SDMA), 1, INT_V}
279
280     O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
281 #undef O
282 };
283
284 #undef OFFSET
285 #define OFFSET(f) Offset(f,struct SAPU *)
286
287 static FreezeData SnapAPU [] = {
288     {OFFSET (Cycles), 4, INT_V},
289     {OFFSET (ShowROM), 1, INT_V},
290     {OFFSET (Flags), 1, INT_V},
291     {OFFSET (KeyedChannels), 1, INT_V},
292     {OFFSET (OutPorts), 4, uint8_ARRAY_V},
293     {OFFSET (DSP), 0x80, uint8_ARRAY_V},
294     {OFFSET (ExtraRAM), 64, uint8_ARRAY_V},
295     {OFFSET (Timer), 3, uint16_ARRAY_V},
296     {OFFSET (TimerTarget), 3, uint16_ARRAY_V},
297     {OFFSET (TimerEnabled), 3, uint8_ARRAY_V},
298     {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V}
299 };
300
301 #undef OFFSET
302 #define OFFSET(f) Offset(f,struct SAPURegisters *)
303
304 static FreezeData SnapAPURegisters [] = {
305     {OFFSET (P)   , 1, INT_V},
306     {OFFSET (YA.W), 2, INT_V},
307     {OFFSET (X)   , 1, INT_V},
308     {OFFSET (S)   , 1, INT_V},
309     {OFFSET (PC)  , 2, INT_V}
310 };
311
312 #undef OFFSET
313 #undef OFFSET1
314 #define OFFSET(f) Offset(f,SSoundData *)
315
316 static FreezeData SnapSoundData [] = {
317     {OFFSET (master_volume_left), 2, INT_V},
318     {OFFSET (master_volume_right), 2, INT_V},
319     {OFFSET (echo_volume_left), 2, INT_V},
320     {OFFSET (echo_volume_right), 2, INT_V},
321     {OFFSET (echo_enable), 4, INT_V},
322     {OFFSET (echo_feedback), 4, INT_V},
323     {OFFSET (echo_ptr), 4, INT_V},
324     {OFFSET (echo_buffer_size), 4, INT_V},
325     {OFFSET (echo_write_enabled), 4, INT_V},
326     {OFFSET (echo_channel_enable), 4, INT_V},
327     {OFFSET (pitch_mod), 4, INT_V},
328     {OFFSET (dummy), 3, uint32_ARRAY_V},
329 #define O(N) \
330     {OFFSET (channels [N].state), 4, INT_V}, \
331     {OFFSET (channels [N].type), 4, INT_V}, \
332     {OFFSET (channels [N].volume_left), 2, INT_V}, \
333     {OFFSET (channels [N].volume_right), 2, INT_V}, \
334     {OFFSET (channels [N].hertz), 4, INT_V}, \
335     {OFFSET (channels [N].count), 4, INT_V}, \
336     {OFFSET (channels [N].loop), 1, INT_V}, \
337     {OFFSET (channels [N].envx), 4, INT_V}, \
338     {OFFSET (channels [N].left_vol_level), 2, INT_V}, \
339     {OFFSET (channels [N].right_vol_level), 2, INT_V}, \
340     {OFFSET (channels [N].envx_target), 2, INT_V}, \
341     {OFFSET (channels [N].env_error), 4, INT_V}, \
342     {OFFSET (channels [N].erate), 4, INT_V}, \
343     {OFFSET (channels [N].direction), 4, INT_V}, \
344     {OFFSET (channels [N].attack_rate), 4, INT_V}, \
345     {OFFSET (channels [N].decay_rate), 4, INT_V}, \
346     {OFFSET (channels [N].sustain_rate), 4, INT_V}, \
347     {OFFSET (channels [N].release_rate), 4, INT_V}, \
348     {OFFSET (channels [N].sustain_level), 4, INT_V}, \
349     {OFFSET (channels [N].sample), 2, INT_V}, \
350     {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V}, \
351     {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V}, \
352     {OFFSET (channels [N].sample_number), 2, INT_V}, \
353     {OFFSET (channels [N].last_block), 1, INT_V}, \
354     {OFFSET (channels [N].needs_decode), 1, INT_V}, \
355     {OFFSET (channels [N].block_pointer), 4, INT_V}, \
356     {OFFSET (channels [N].sample_pointer), 4, INT_V}, \
357     {OFFSET (channels [N].mode), 4, INT_V}
358
359     O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
360 #undef O
361 };
362
363 #ifdef USE_SA1
364
365 #undef OFFSET
366 #define OFFSET(f) Offset(f,struct SSA1Registers *)
367
368 static FreezeData SnapSA1Registers [] = {
369     {OFFSET (PB),  1, INT_V},
370     {OFFSET (DB),  1, INT_V},
371     {OFFSET (P.W), 2, INT_V},
372     {OFFSET (A.W), 2, INT_V},
373     {OFFSET (D.W), 2, INT_V},
374     {OFFSET (S.W), 2, INT_V},
375     {OFFSET (X.W), 2, INT_V},
376     {OFFSET (Y.W), 2, INT_V},
377     {OFFSET (PC),  2, INT_V}
378 };
379
380 #undef OFFSET
381 #define OFFSET(f) Offset(f,struct SSA1 *)
382
383 static FreezeData SnapSA1 [] = {
384     {OFFSET (Flags), 4, INT_V},
385     {OFFSET (NMIActive), 1, INT_V},
386     {OFFSET (IRQActive), 1, INT_V},
387     {OFFSET (WaitingForInterrupt), 1, INT_V},
388     {OFFSET (op1), 2, INT_V},
389     {OFFSET (op2), 2, INT_V},
390     {OFFSET (arithmetic_op), 4, INT_V},
391     {OFFSET (sum), 8, INT_V},
392     {OFFSET (overflow), 1, INT_V}
393 };
394 #endif
395
396 static STREAM ss_st;
397
398 static void Freeze ();
399 static int Unfreeze ();
400 static void FreezeStruct (const char *name, void *base, FreezeData *fields,
401                    int num_fields);
402 static void FreezeBlock (const char *name, uint8 *block, int size);
403
404 static int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
405                     int num_fields);
406 static int UnfreezeBlock (const char *name, uint8 *block, int size);
407
408 bool8 S9xFreezeGame (const char *filename)
409 {
410     if ((ss_st = OPEN_STREAM(filename, "wb")))
411     {
412                 Freeze();
413                 CLOSE_STREAM(ss_st);
414                 return (TRUE);
415     }
416     return (FALSE);
417 }
418
419
420 bool8 S9xUnfreezeGame (const char *filename)
421 {
422     if ((ss_st = OPEN_STREAM(filename, "rb")))
423     {
424                 int result;
425                 if ((result = Unfreeze()) != SUCCESS)
426                 {
427                         switch (result)
428                         {
429                         case WRONG_FORMAT:
430                         S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT, 
431                                         "File not in Snes9x freeze format");
432                         S9xReset();
433                         break;
434                         case WRONG_VERSION:
435                         S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
436                                         "Incompatable Snes9x freeze file format version");
437                         S9xReset();
438                         break;
439                         default:
440                         // should never happen
441                         break;
442                         }
443                         CLOSE_STREAM(ss_st);
444                         return FALSE;
445                 }
446                 CLOSE_STREAM(ss_st);
447                 return TRUE;
448     }
449
450     
451     return FALSE;
452 }
453
454 static void Freeze ()
455 {
456     char buffer[1024];
457     int i;
458
459     S9xSetSoundMute (TRUE);
460 #ifdef ZSNES_FX
461     if (Settings.SuperFX)
462         S9xSuperFXPreSaveState ();
463 #endif
464
465     S9xSRTCPreSaveState ();
466
467     for (i = 0; i < 8; i++)
468     {
469         SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
470         SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
471     }
472     sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
473     WRITE_STREAM(buffer, strlen(buffer), ss_st);
474     sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
475              Memory.ROMFilename, 0);
476     WRITE_STREAM(buffer, strlen(buffer) + 1, ss_st);
477     FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
478     FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
479     FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
480     FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
481
482 // RAM and VRAM
483     FreezeBlock ("VRA", Memory.VRAM, 0x10000);
484     FreezeBlock ("RAM", Memory.RAM, 0x20000);
485     FreezeBlock ("SRA", ::SRAM, 0x20000);
486     FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
487     if (Settings.APUEnabled)
488     {
489 // APU
490         FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
491         // copy all SPC700 regs to savestate compatible struct
492         SAPURegisters spcregs;
493         spcregs.P  = IAPU.P;
494         spcregs.YA.W = IAPU.YA.W;
495         spcregs.X  = IAPU.X;
496         spcregs.S  = IAPU.S;
497         spcregs.PC = IAPU.PC - IAPU.RAM;
498         FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
499                       COUNT (SnapAPURegisters));
500
501         FreezeBlock  ("ARA", IAPU.RAM, 0x10000);
502         FreezeStruct ("SOU", &SoundData, SnapSoundData,
503                       COUNT (SnapSoundData));
504     }
505 #ifdef USE_SA1
506     if (Settings.SA1)
507     {
508         SA1Registers.PC = SA1.PC - SA1.PCBase;
509         S9xSA1PackStatus ();
510         FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
511         FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers, 
512                       COUNT (SnapSA1Registers));
513     }
514 #endif
515         S9xSetSoundMute (FALSE);
516 #ifdef ZSNES_FX
517     if (Settings.SuperFX)
518         S9xSuperFXPostSaveState ();
519 #endif
520 }
521
522 static int Unfreeze()
523 {
524     char buffer[16];
525     char rom_filename[1024];
526     int result;
527
528     int version;
529     int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
530     if (READ_STREAM(buffer, len, ss_st) != len)
531     {
532                 printf("%s: Failed to read header\n", __func__);
533                 return WRONG_FORMAT;
534         }
535     if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
536     {
537                 printf("%s: Read header not correct\n", __func__);
538                 return WRONG_FORMAT;
539         }
540     if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
541         {
542                 printf("%s: Wrong version\n", __func__);
543                 return WRONG_VERSION;
544         }
545
546     if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 1024)) != SUCCESS)
547         {
548                 printf("%s: UnfreezeBlock NAM failed (corrupt)\n", __func__);
549                 return result;
550         }
551         
552     if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
553         strcasecmp (PathBasename(rom_filename), PathBasename(Memory.ROMFilename)) != 0)
554     {
555                 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
556                     "Current loaded ROM image doesn't match that required by freeze-game file.");
557     }
558
559
560     uint32 old_flags = CPU.Flags;
561 #ifdef USE_SA1
562     uint32 sa1_old_flags = SA1.Flags;
563 #endif
564         S9xReset ();
565     S9xSetSoundMute (TRUE);
566
567     if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU, 
568                                   COUNT (SnapCPU))) != SUCCESS)
569         return (result);
570         
571         
572     Memory.FixROMSpeed ();
573     CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
574                               SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
575     if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
576         return (result);
577     if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
578         return (result);
579         
580
581     IPPU.ColorsChanged = TRUE;
582     IPPU.OBJChanged = TRUE;
583     CPU.InDMA = FALSE;
584     S9xFixColourBrightness ();
585     IPPU.RenderThisFrame = FALSE;
586
587     if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA, 
588                                   COUNT (SnapDMA))) != SUCCESS)
589         return (result);
590         
591     if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
592         return (result);                
593         
594     if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
595         return (result);
596
597     if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
598         return (result);
599
600     if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
601         return (result);
602
603         
604     if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
605     {
606                 SAPURegisters spcregs;
607                 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
608                                       COUNT (SnapAPURegisters))) != SUCCESS)
609                     return (result);
610                 // reload all SPC700 regs from savestate compatible struct
611                 IAPU.P = spcregs.P;
612                 IAPU.YA.W = spcregs.YA.W;
613                 IAPU.X = spcregs.X;
614                 IAPU.S = spcregs.S;
615                 IAPU.PC = IAPU.RAM + spcregs.PC;
616
617                 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
618                     return (result);
619                     
620                 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
621                                       COUNT (SnapSoundData))) != SUCCESS)
622                     return (result);
623             
624             // notaz: just to be sure
625                 for(int u=0; u<8; u++) {
626                         SoundData.channels[u].env_ind_attack &= 0xf;
627                         SoundData.channels[u].env_ind_decay  &= 0x7;
628                         SoundData.channels[u].env_ind_sustain&= 0x1f;
629                 }
630
631                 S9xSetSoundMute (FALSE);
632                 S9xAPUUnpackStatus ();
633                 if (APUCheckDirectPage ())
634                         IAPU.DirectPage = IAPU.RAM + 0x100;
635                 else
636                         IAPU.DirectPage = IAPU.RAM;
637                 Settings.APUEnabled = TRUE;
638                 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
639     }
640     else
641     {
642         Settings.APUEnabled = FALSE;
643         /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
644         S9xSetSoundMute (TRUE);
645     }
646 #ifdef USE_SA1
647     if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1, 
648                                   COUNT(SnapSA1))) == SUCCESS)
649     {
650         if ((result = UnfreezeStruct ("SAR", &SA1Registers, 
651                                       SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
652             return (result);
653
654         S9xFixSA1AfterSnapshotLoad ();
655         SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
656     }
657 #endif
658     S9xFixSoundAfterSnapshotLoad ();
659     ICPU.ShiftedPB = Registers.PB << 16;
660     ICPU.ShiftedDB = Registers.DB << 16;
661     S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
662     
663     
664     //S9xUnpackStatus (); // not needed
665     //S9xFixCycles (); // also not needed?
666     S9xReschedule ();
667 #ifdef ZSNES_FX
668     if (Settings.SuperFX)
669         S9xSuperFXPostLoadState ();
670 #endif
671
672     S9xSRTCPostLoadState ();
673     if (Settings.SDD1)  S9xSDD1PostLoadState ();
674     
675     return (SUCCESS);
676 }
677
678 int FreezeSize (int size, int type)
679 {
680     switch (type)
681     {
682     case uint16_ARRAY_V:
683         return (size * 2);
684     case uint32_ARRAY_V:
685         return (size * 4);
686     default:
687         return (size);
688     }
689 }
690
691 void FreezeStruct(const char *name, void *base, FreezeData *fields,
692                    int num_fields)
693 {
694     // Work out the size of the required block
695     int len = 0;
696     int i;
697     int j;
698
699     for (i = 0; i < num_fields; i++)
700     {
701         if (fields [i].offset + FreezeSize (fields [i].size, 
702                                             fields [i].type) > len)
703             len = fields [i].offset + FreezeSize (fields [i].size, 
704                                                   fields [i].type);
705     }
706
707 //    uint8 *block = new uint8 [len];
708     uint8 *block = (uint8*)malloc(len);
709     uint8 *ptr = block;
710     uint16 word;
711     uint32 dword;
712     int64  qword;
713
714     // Build the block ready to be streamed out
715     for (i = 0; i < num_fields; i++)
716     {
717         switch (fields [i].type)
718         {
719         case INT_V:
720             switch (fields [i].size)
721             {
722             case 1:
723                 *ptr++ = *((uint8 *) base + fields [i].offset);
724                 break;
725             case 2:
726                 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
727                 *ptr++ = (uint8) (word >> 8);
728                 *ptr++ = (uint8) word;
729                 break;
730             case 4:
731                 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
732                 *ptr++ = (uint8) (dword >> 24);
733                 *ptr++ = (uint8) (dword >> 16);
734                 *ptr++ = (uint8) (dword >> 8);
735                 *ptr++ = (uint8) dword;
736                 break;
737             case 8:
738                 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
739                 *ptr++ = (uint8) (qword >> 56);
740                 *ptr++ = (uint8) (qword >> 48);
741                 *ptr++ = (uint8) (qword >> 40);
742                 *ptr++ = (uint8) (qword >> 32);
743                 *ptr++ = (uint8) (qword >> 24);
744                 *ptr++ = (uint8) (qword >> 16);
745                 *ptr++ = (uint8) (qword >> 8);
746                 *ptr++ = (uint8) qword;
747                 break;
748             }
749             break;
750         case uint8_ARRAY_V:
751             memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
752             ptr += fields [i].size;
753             break;
754         case uint16_ARRAY_V:
755             for (j = 0; j < fields [i].size; j++)
756             {
757                 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
758                 *ptr++ = (uint8) (word >> 8);
759                 *ptr++ = (uint8) word;
760             }
761             break;
762         case uint32_ARRAY_V:
763             for (j = 0; j < fields [i].size; j++)
764             {
765                 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
766                 *ptr++ = (uint8) (dword >> 24);
767                 *ptr++ = (uint8) (dword >> 16);
768                 *ptr++ = (uint8) (dword >> 8);
769                 *ptr++ = (uint8) dword;
770             }
771             break;
772         }
773     }
774
775     FreezeBlock (name, block, len);
776
777         free(block);
778 }
779
780 void FreezeBlock (const char *name, uint8 *block, int size)
781 {
782     char buffer [512];
783     sprintf (buffer, "%s:%06d:", name, size);
784     WRITE_STREAM(buffer, strlen(buffer), ss_st);
785     WRITE_STREAM(block, size, ss_st);
786 }
787
788 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
789                      int num_fields)
790 {
791     // Work out the size of the required block
792     int len = 0;
793     int i;
794     int j;
795
796     for (i = 0; i < num_fields; i++)
797     {
798         if (fields [i].offset + FreezeSize (fields [i].size, 
799                                             fields [i].type) > len)
800             len = fields [i].offset + FreezeSize (fields [i].size, 
801                                                   fields [i].type);
802     }
803
804         uint8 *block = (uint8*)malloc(len);
805     uint8 *ptr = block;
806     uint16 word;
807     uint32 dword;
808     int64  qword;
809     int result;
810
811     if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
812     {
813         free(block);
814         return (result);
815     }
816
817     // Unpack the block of data into a C structure
818     for (i = 0; i < num_fields; i++)
819     {
820         switch (fields [i].type)
821         {
822         case INT_V:
823             switch (fields [i].size)
824             {
825             case 1:
826                 *((uint8 *) base + fields [i].offset) = *ptr++;
827                 break;
828             case 2:
829                 word  = *ptr++ << 8;
830                 word |= *ptr++;
831                 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
832                 break;
833             case 4:
834                 dword  = *ptr++ << 24;
835                 dword |= *ptr++ << 16;
836                 dword |= *ptr++ << 8;
837                 dword |= *ptr++;
838                 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
839                 break;
840             case 8:
841                 qword  = (int64) *ptr++ << 56;
842                 qword |= (int64) *ptr++ << 48;
843                 qword |= (int64) *ptr++ << 40;
844                 qword |= (int64) *ptr++ << 32;
845                 qword |= (int64) *ptr++ << 24;
846                 qword |= (int64) *ptr++ << 16;
847                 qword |= (int64) *ptr++ << 8;
848                 qword |= (int64) *ptr++;
849                 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
850                 break;
851             }
852             break;
853         case uint8_ARRAY_V:
854             memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
855             ptr += fields [i].size;
856             break;
857         case uint16_ARRAY_V:
858             for (j = 0; j < fields [i].size; j++)
859             {
860                 word  = *ptr++ << 8;
861                 word |= *ptr++;
862                 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
863             }
864             break;
865         case uint32_ARRAY_V:
866             for (j = 0; j < fields [i].size; j++)
867             {
868                 dword  = *ptr++ << 24;
869                 dword |= *ptr++ << 16;
870                 dword |= *ptr++ << 8;
871                 dword |= *ptr++;
872                 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
873             }
874             break;
875         }
876     }
877
878 //    delete block;
879         free(block);
880     return (result);
881 }
882
883 int UnfreezeBlock(const char *name, uint8 *block, int size)
884 {
885     char buffer [20];
886     int len = 0;
887     int rem = 0;
888
889     if (READ_STREAM(buffer, 11, ss_st) != 11 ||
890         strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
891         (len = atoi (&buffer [4])) == 0)
892     {
893                 printf("%s: %s: Invalid block header\n", __func__, name);
894                 return WRONG_FORMAT;
895     }
896     
897     if (len > size)
898     {
899                 rem = len - size;
900                 len = size;
901     }
902
903     if (READ_STREAM(block, len, ss_st) != len)
904     {
905                 printf("%s: Invalid block\n", __func__);
906                 return WRONG_FORMAT;
907         }
908         
909     if (rem)
910     {
911                 char *junk = (char*)malloc(rem);
912                 READ_STREAM(junk, rem, ss_st);
913                 free(junk);
914     }
915
916     return SUCCESS;
917 }
918
919