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