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