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