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