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