minor filename fixes
[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 Snapshot (const char *filename)
421 {
422     return (S9xFreezeGame (filename));
423 }
424
425 bool8 S9xFreezeGame (const char *filename)
426 {
427     if(statef_open(filename, "wb"))
428     {
429                 Freeze();
430                 statef_close();
431                 return (TRUE);
432     }
433     return (FALSE);
434 }
435
436
437 bool8 S9xUnfreezeGame (const char *filename)
438 {
439     if(statef_open(filename, "rb"))
440     {
441                 int result;
442                 if ((result = Unfreeze()) != SUCCESS)
443                 {
444                         switch (result)
445                         {
446                         case WRONG_FORMAT:
447                         S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT, 
448                                         "File not in Snes9x freeze format");
449                         S9xReset();
450                         break;
451                         case WRONG_VERSION:
452                         S9xMessage (S9X_ERROR, S9X_WRONG_VERSION,
453                                         "Incompatable Snes9x freeze file format version");
454                         S9xReset();
455                         break;
456                         default:
457                         // should never happen
458                         break;
459                         }
460                         statef_close();
461                         return (FALSE);
462                 }
463                 statef_close();
464                 return (TRUE);
465     }
466
467     
468     return (FALSE);
469 }
470
471 static void Freeze ()
472 {
473     char buffer[1024];
474     int i;
475
476     S9xSetSoundMute (TRUE);
477 #ifdef ZSNES_FX
478     if (Settings.SuperFX)
479         S9xSuperFXPreSaveState ();
480 #endif
481
482     S9xSRTCPreSaveState ();
483
484     for (i = 0; i < 8; i++)
485     {
486         SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0];
487         SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1];
488     }
489     sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
490     statef_write(buffer, strlen (buffer));
491     sprintf (buffer, "NAM:%06d:%s%c", strlen (Memory.ROMFilename) + 1,
492              Memory.ROMFilename, 0);
493     statef_write(buffer, strlen (buffer) + 1);
494     FreezeStruct ("CPU", &CPU, SnapCPU, COUNT (SnapCPU));
495     FreezeStruct ("REG", &Registers, SnapRegisters, COUNT (SnapRegisters));
496     FreezeStruct ("PPU", &PPU, SnapPPU, COUNT (SnapPPU));
497     FreezeStruct ("DMA", DMA, SnapDMA, COUNT (SnapDMA));
498
499 // RAM and VRAM
500     FreezeBlock ("VRA", Memory.VRAM, 0x10000);
501     FreezeBlock ("RAM", Memory.RAM, 0x20000);
502     FreezeBlock ("SRA", ::SRAM, 0x20000);
503     FreezeBlock ("FIL", Memory.FillRAM, 0x8000);
504     if (Settings.APUEnabled)
505     {
506 // APU
507         FreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU));
508         // copy all SPC700 regs to savestate compatible struct
509         SAPURegisters spcregs;
510         spcregs.P  = IAPU.P;
511         spcregs.YA.W = IAPU.YA.W;
512         spcregs.X  = IAPU.X;
513         spcregs.S  = IAPU.S;
514         spcregs.PC = IAPU.PC - IAPU.RAM;
515         FreezeStruct ("ARE", &spcregs, SnapAPURegisters,
516                       COUNT (SnapAPURegisters));
517
518         FreezeBlock  ("ARA", IAPU.RAM, 0x10000);
519         FreezeStruct ("SOU", &SoundData, SnapSoundData,
520                       COUNT (SnapSoundData));
521     }
522 #ifdef USE_SA1
523     if (Settings.SA1)
524     {
525         SA1Registers.PC = SA1.PC - SA1.PCBase;
526         S9xSA1PackStatus ();
527         FreezeStruct ("SA1", &SA1, SnapSA1, COUNT (SnapSA1));
528         FreezeStruct ("SAR", &SA1Registers, SnapSA1Registers, 
529                       COUNT (SnapSA1Registers));
530     }
531 #endif
532         S9xSetSoundMute (FALSE);
533 #ifdef ZSNES_FX
534     if (Settings.SuperFX)
535         S9xSuperFXPostSaveState ();
536 #endif
537 }
538
539 static int Unfreeze()
540 {
541         // notaz: overflowing the damn Symbian stack again
542     char buffer [16];
543     char rom_filename [512];
544     int result;
545
546     int version;
547     unsigned int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1;
548     if (statef_read(buffer, len) != (int)len)
549     {
550                 printf("failed to read header\r\n");
551                 return (WRONG_FORMAT);
552         }
553     if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0)
554     {
555                 printf("read header not correct\r\n");
556                 return (WRONG_FORMAT);
557         }
558     if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION)
559         {
560                 printf("Wrong version\r\n");
561                 return (WRONG_VERSION);
562         }
563         
564     if ((result = UnfreezeBlock("NAM", (uint8 *) rom_filename, 512)) != SUCCESS)
565         {
566                 printf("UnfreezeBlock NAM failed\r\n");
567                 return (result);
568         }
569         
570     if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 &&
571         strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0)
572     {
573                 S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME,
574                     "Current loaded ROM image doesn't match that required by freeze-game file.");
575                 printf("filename mismatch\r\n");
576     }
577     
578     
579
580     uint32 old_flags = CPU.Flags;
581 #ifdef USE_SA1
582     uint32 sa1_old_flags = SA1.Flags;
583 #endif
584         S9xReset ();
585     S9xSetSoundMute (TRUE);
586
587     if ((result = UnfreezeStruct("CPU", &CPU, SnapCPU, 
588                                   COUNT (SnapCPU))) != SUCCESS)
589         return (result);
590         
591         
592     Memory.FixROMSpeed ();
593     CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG |
594                               SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
595     if ((result = UnfreezeStruct("REG", &Registers, SnapRegisters, COUNT (SnapRegisters))) != SUCCESS)
596         return (result);
597     if ((result = UnfreezeStruct("PPU", &PPU, SnapPPU, COUNT (SnapPPU))) != SUCCESS)
598         return (result);
599         
600
601     IPPU.ColorsChanged = TRUE;
602     IPPU.OBJChanged = TRUE;
603     CPU.InDMA = FALSE;
604     S9xFixColourBrightness ();
605     IPPU.RenderThisFrame = FALSE;
606
607     if ((result = UnfreezeStruct ("DMA", DMA, SnapDMA, 
608                                   COUNT (SnapDMA))) != SUCCESS)
609         return (result);
610         
611     if ((result = UnfreezeBlock ("VRA", Memory.VRAM, 0x10000)) != SUCCESS)
612         return (result);                
613         
614     if ((result = UnfreezeBlock ("RAM", Memory.RAM, 0x20000)) != SUCCESS)
615         return (result);
616
617     if ((result = UnfreezeBlock ("SRA", ::SRAM, 0x20000)) != SUCCESS)
618         return (result);
619
620     if ((result = UnfreezeBlock ("FIL", Memory.FillRAM, 0x8000)) != SUCCESS)
621         return (result);
622
623         
624     if (UnfreezeStruct ("APU", &APU, SnapAPU, COUNT (SnapAPU)) == SUCCESS)
625     {
626                 SAPURegisters spcregs;
627                 if ((result = UnfreezeStruct ("ARE", &spcregs, SnapAPURegisters,
628                                       COUNT (SnapAPURegisters))) != SUCCESS)
629                     return (result);
630                 // reload all SPC700 regs from savestate compatible struct
631                 IAPU.P = spcregs.P;
632                 IAPU.YA.W = spcregs.YA.W;
633                 IAPU.X = spcregs.X;
634                 IAPU.S = spcregs.S;
635                 IAPU.PC = IAPU.RAM + spcregs.PC;
636
637                 if ((result = UnfreezeBlock ("ARA", IAPU.RAM, 0x10000)) != SUCCESS)
638                     return (result);
639                     
640                 if ((result = UnfreezeStruct ("SOU", &SoundData, SnapSoundData,
641                                       COUNT (SnapSoundData))) != SUCCESS)
642                     return (result);
643             
644             // notaz: just to be sure
645                 for(int u=0; u<8; u++) {
646                         SoundData.channels[u].env_ind_attack &= 0xf;
647                         SoundData.channels[u].env_ind_decay  &= 0x7;
648                         SoundData.channels[u].env_ind_sustain&= 0x1f;
649                 }
650
651                 S9xSetSoundMute (FALSE);
652                 S9xAPUUnpackStatus ();
653                 if (APUCheckDirectPage ())
654                         IAPU.DirectPage = IAPU.RAM + 0x100;
655                 else
656                         IAPU.DirectPage = IAPU.RAM;
657                 Settings.APUEnabled = TRUE;
658                 /*IAPU.APUExecuting*/CPU.APU_APUExecuting = TRUE;
659     }
660     else
661     {
662         Settings.APUEnabled = FALSE;
663         /*IAPU.APUExecuting*/CPU.APU_APUExecuting = FALSE;
664         S9xSetSoundMute (TRUE);
665     }
666 #ifdef USE_SA1
667     if ((result = UnfreezeStruct ("SA1", &SA1, SnapSA1, 
668                                   COUNT(SnapSA1))) == SUCCESS)
669     {
670         if ((result = UnfreezeStruct ("SAR", &SA1Registers, 
671                                       SnapSA1Registers, COUNT (SnapSA1Registers))) != SUCCESS)
672             return (result);
673
674         S9xFixSA1AfterSnapshotLoad ();
675         SA1.Flags |= sa1_old_flags & (TRACE_FLAG);
676     }
677 #endif
678     S9xFixSoundAfterSnapshotLoad ();
679     ICPU.ShiftedPB = Registers.PB << 16;
680     ICPU.ShiftedDB = Registers.DB << 16;
681     S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
682     
683     
684     //S9xUnpackStatus (); // not needed
685     //S9xFixCycles (); // also not needed?
686     S9xReschedule ();
687 #ifdef ZSNES_FX
688     if (Settings.SuperFX)
689         S9xSuperFXPostLoadState ();
690 #endif
691
692     S9xSRTCPostLoadState ();
693     if (Settings.SDD1)  S9xSDD1PostLoadState ();
694     
695     return (SUCCESS);
696 }
697
698 int FreezeSize (int size, int type)
699 {
700     switch (type)
701     {
702     case uint16_ARRAY_V:
703         return (size * 2);
704     case uint32_ARRAY_V:
705         return (size * 4);
706     default:
707         return (size);
708     }
709 }
710
711 void FreezeStruct(const char *name, void *base, FreezeData *fields,
712                    int num_fields)
713 {
714     // Work out the size of the required block
715     int len = 0;
716     int i;
717     int j;
718
719     for (i = 0; i < num_fields; i++)
720     {
721         if (fields [i].offset + FreezeSize (fields [i].size, 
722                                             fields [i].type) > len)
723             len = fields [i].offset + FreezeSize (fields [i].size, 
724                                                   fields [i].type);
725     }
726
727 //    uint8 *block = new uint8 [len];
728     uint8 *block = (uint8*)malloc(len);
729     uint8 *ptr = block;
730     uint16 word;
731     uint32 dword;
732     int64  qword;
733
734     // Build the block ready to be streamed out
735     for (i = 0; i < num_fields; i++)
736     {
737         switch (fields [i].type)
738         {
739         case INT_V:
740             switch (fields [i].size)
741             {
742             case 1:
743                 *ptr++ = *((uint8 *) base + fields [i].offset);
744                 break;
745             case 2:
746                 word = *((uint16 *) ((uint8 *) base + fields [i].offset));
747                 *ptr++ = (uint8) (word >> 8);
748                 *ptr++ = (uint8) word;
749                 break;
750             case 4:
751                 dword = *((uint32 *) ((uint8 *) base + fields [i].offset));
752                 *ptr++ = (uint8) (dword >> 24);
753                 *ptr++ = (uint8) (dword >> 16);
754                 *ptr++ = (uint8) (dword >> 8);
755                 *ptr++ = (uint8) dword;
756                 break;
757             case 8:
758                 qword = *((int64 *) ((uint8 *) base + fields [i].offset));
759                 *ptr++ = (uint8) (qword >> 56);
760                 *ptr++ = (uint8) (qword >> 48);
761                 *ptr++ = (uint8) (qword >> 40);
762                 *ptr++ = (uint8) (qword >> 32);
763                 *ptr++ = (uint8) (qword >> 24);
764                 *ptr++ = (uint8) (qword >> 16);
765                 *ptr++ = (uint8) (qword >> 8);
766                 *ptr++ = (uint8) qword;
767                 break;
768             }
769             break;
770         case uint8_ARRAY_V:
771             memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size);
772             ptr += fields [i].size;
773             break;
774         case uint16_ARRAY_V:
775             for (j = 0; j < fields [i].size; j++)
776             {
777                 word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2));
778                 *ptr++ = (uint8) (word >> 8);
779                 *ptr++ = (uint8) word;
780             }
781             break;
782         case uint32_ARRAY_V:
783             for (j = 0; j < fields [i].size; j++)
784             {
785                 dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4));
786                 *ptr++ = (uint8) (dword >> 24);
787                 *ptr++ = (uint8) (dword >> 16);
788                 *ptr++ = (uint8) (dword >> 8);
789                 *ptr++ = (uint8) dword;
790             }
791             break;
792         }
793     }
794
795     FreezeBlock (name, block, len);
796
797         free(block);
798 }
799
800 void FreezeBlock (const char *name, uint8 *block, int size)
801 {
802     char buffer [512];
803     sprintf (buffer, "%s:%06d:", name, size);
804     statef_write(buffer, strlen (buffer));
805     statef_write(block, size);
806 }
807
808 int UnfreezeStruct (const char *name, void *base, FreezeData *fields,
809                      int num_fields)
810 {
811     // Work out the size of the required block
812     int len = 0;
813     int i;
814     int j;
815
816     for (i = 0; i < num_fields; i++)
817     {
818         if (fields [i].offset + FreezeSize (fields [i].size, 
819                                             fields [i].type) > len)
820             len = fields [i].offset + FreezeSize (fields [i].size, 
821                                                   fields [i].type);
822     }
823
824         uint8 *block = (uint8*)malloc(len);
825     uint8 *ptr = block;
826     uint16 word;
827     uint32 dword;
828     int64  qword;
829     int result;
830
831     if ((result = UnfreezeBlock (name, block, len)) != SUCCESS)
832     {
833         free(block);
834         return (result);
835     }
836
837     // Unpack the block of data into a C structure
838     for (i = 0; i < num_fields; i++)
839     {
840         switch (fields [i].type)
841         {
842         case INT_V:
843             switch (fields [i].size)
844             {
845             case 1:
846                 *((uint8 *) base + fields [i].offset) = *ptr++;
847                 break;
848             case 2:
849                 word  = *ptr++ << 8;
850                 word |= *ptr++;
851                 *((uint16 *) ((uint8 *) base + fields [i].offset)) = word;
852                 break;
853             case 4:
854                 dword  = *ptr++ << 24;
855                 dword |= *ptr++ << 16;
856                 dword |= *ptr++ << 8;
857                 dword |= *ptr++;
858                 *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword;
859                 break;
860             case 8:
861                 qword  = (int64) *ptr++ << 56;
862                 qword |= (int64) *ptr++ << 48;
863                 qword |= (int64) *ptr++ << 40;
864                 qword |= (int64) *ptr++ << 32;
865                 qword |= (int64) *ptr++ << 24;
866                 qword |= (int64) *ptr++ << 16;
867                 qword |= (int64) *ptr++ << 8;
868                 qword |= (int64) *ptr++;
869                 *((int64 *) ((uint8 *) base + fields [i].offset)) = qword;
870                 break;
871             }
872             break;
873         case uint8_ARRAY_V:
874             memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size);
875             ptr += fields [i].size;
876             break;
877         case uint16_ARRAY_V:
878             for (j = 0; j < fields [i].size; j++)
879             {
880                 word  = *ptr++ << 8;
881                 word |= *ptr++;
882                 *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word;
883             }
884             break;
885         case uint32_ARRAY_V:
886             for (j = 0; j < fields [i].size; j++)
887             {
888                 dword  = *ptr++ << 24;
889                 dword |= *ptr++ << 16;
890                 dword |= *ptr++ << 8;
891                 dword |= *ptr++;
892                 *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword;
893             }
894             break;
895         }
896     }
897
898 //    delete block;
899         free(block);
900     return (result);
901 }
902
903 int UnfreezeBlock(const char *name, uint8 *block, int size)
904 {
905     char buffer [20];
906     int len = 0;
907     int rem = 0;
908     printf("UnfreezeBlock: %s\r\n",name);
909     if (statef_read(buffer, 11) != 11 ||
910         strncmp (buffer, name, 3) != 0 || buffer [3] != ':' ||
911         (len = atoi (&buffer [4])) == 0)
912     {
913                 printf("UnfreezeBlock err1\n");
914                 return (WRONG_FORMAT);
915     }
916     
917     if (len > size)
918     {
919                 rem = len - size;
920                 len = size;
921     }
922     
923     if (statef_read(block, len) != len)
924     {
925                 printf("UnfreezeBlock err2\n");
926                 return (WRONG_FORMAT);
927         }
928         
929     if (rem)
930     {
931                 char *junk = (char*)malloc(rem);
932                 statef_read(junk, rem);
933                 free(junk);
934     }
935         
936     return (SUCCESS);
937 }
938
939