1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include <assert.h>
8#include "snes9x.h"
9#include "memmap.h"
10#include "dma.h"
11#include "apu/apu.h"
12#include "fxinst.h"
13#include "fxemu.h"
14#include "sdd1.h"
15#include "srtc.h"
16#include "snapshot.h"
17#include "controls.h"
18#include "movie.h"
19#include "display.h"
20#include "language.h"
21#include "gfx.h"
22
23#ifndef min
24#define min(a,b) (((a) < (b)) ? (a) : (b))
25#endif
26
27typedef struct
28{
29 int offset;
30 int offset2;
31 int size;
32 int type;
33 uint16 debuted_in;
34 uint16 deleted_in;
35 const char *name;
36} FreezeData;
37
38enum
39{
40 INT_V,
41 uint8_ARRAY_V,
42 uint16_ARRAY_V,
43 uint32_ARRAY_V,
44 uint8_INDIR_ARRAY_V,
45 uint16_INDIR_ARRAY_V,
46 uint32_INDIR_ARRAY_V,
47 POINTER_V
48};
49
50#define COUNT(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
51#define Offset(field, structure) ((int) (((char *) (&(((structure) NULL)->field))) - ((char *) NULL)))
52#define OFFSET(f) Offset(f, STRUCT *)
53#define DUMMY(f) Offset(f, struct Obsolete *)
54#define DELETED(f) (-1)
55
56#define INT_ENTRY(save_version_introduced, field) \
57{ \
58 OFFSET(field), \
59 0, \
60 sizeof(((STRUCT *) NULL)->field), \
61 INT_V, \
62 save_version_introduced, \
63 9999, \
64 #field \
65}
66
67#define ARRAY_ENTRY(save_version_introduced, field, count, elemType) \
68{ \
69 OFFSET(field), \
70 0, \
71 count, \
72 elemType, \
73 save_version_introduced, \
74 9999, \
75 #field \
76}
77
78#define POINTER_ENTRY(save_version_introduced, field, relativeToField) \
79{ \
80 OFFSET(field), \
81 OFFSET(relativeToField), \
82 4, \
83 POINTER_V, \
84 save_version_introduced, \
85 9999, \
86 #field \
87}
88
89#define OBSOLETE_INT_ENTRY(save_version_introduced, save_version_removed, field) \
90{ \
91 DUMMY(field), \
92 0, \
93 sizeof(((struct Obsolete *) NULL)->field), \
94 INT_V, \
95 save_version_introduced, \
96 save_version_removed, \
97 #field \
98}
99
100#define OBSOLETE_ARRAY_ENTRY(save_version_introduced, save_version_removed, field, count, elemType) \
101{ \
102 DUMMY(field), \
103 0, \
104 count, \
105 elemType, \
106 save_version_introduced, \
107 save_version_removed, \
108 #field \
109}
110
111#define OBSOLETE_POINTER_ENTRY(save_version_introduced, save_version_removed, field, relativeToField) \
112{ \
113 DUMMY(field), \
114 DUMMY(relativeToField), \
115 4, \
116 POINTER_V, \
117 save_version_introduced, \
118 save_version_removed, \
119 #field \
120}
121
122#define DELETED_INT_ENTRY(save_version_introduced, save_version_removed, field, size) \
123{ \
124 DELETED(field), \
125 0, \
126 size, \
127 INT_V, \
128 save_version_introduced, \
129 save_version_removed, \
130 #field \
131}
132
133#define DELETED_ARRAY_ENTRY(save_version_introduced, save_version_removed, field, count, elemType) \
134{ \
135 DELETED(field), \
136 0, \
137 count, \
138 elemType, \
139 save_version_introduced, \
140 save_version_removed, \
141 #field \
142}
143
144#define DELETED_POINTER_ENTRY(save_version_introduced, save_version_removed, field, relativeToField) \
145{ \
146 DELETED(field), \
147 DELETED(relativeToField), \
148 4, \
149 POINTER_V, \
150 save_version_introduced, \
151 save_version_removed, \
152 #field \
153}
154
155struct SDMASnapshot
156{
157 struct SDMA dma[8];
158};
159
160struct SnapshotMovieInfo
161{
162 uint32 MovieInputDataSize;
163};
164
165struct SnapshotScreenshotInfo
166{
167 uint16 Width;
168 uint16 Height;
169 uint8 Interlaced;
170 uint8 Data[MAX_SNES_WIDTH * MAX_SNES_HEIGHT * 3];
171};
172
173static struct Obsolete
174{
175 uint8 CPU_IRQActive;
176} Obsolete;
177
178#define STRUCT struct SCPUState
179
180static FreezeData SnapCPU[] =
181{
182 INT_ENTRY(6, Cycles),
183 INT_ENTRY(6, PrevCycles),
184 INT_ENTRY(6, V_Counter),
185 INT_ENTRY(6, Flags),
186 OBSOLETE_INT_ENTRY(6, 7, CPU_IRQActive),
187 INT_ENTRY(6, IRQPending),
188 INT_ENTRY(6, MemSpeed),
189 INT_ENTRY(6, MemSpeedx2),
190 INT_ENTRY(6, FastROMSpeed),
191 INT_ENTRY(6, InDMA),
192 INT_ENTRY(6, InHDMA),
193 INT_ENTRY(6, InDMAorHDMA),
194 INT_ENTRY(6, InWRAMDMAorHDMA),
195 INT_ENTRY(6, HDMARanInDMA),
196 INT_ENTRY(6, WhichEvent),
197 INT_ENTRY(6, NextEvent),
198 INT_ENTRY(6, WaitingForInterrupt),
199 DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
200 DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
201 DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
202 INT_ENTRY(7, NMIPending),
203 INT_ENTRY(7, IRQLine),
204 INT_ENTRY(7, IRQTransition),
205 INT_ENTRY(7, IRQLastState),
206 INT_ENTRY(7, IRQExternal)
207};
208
209#undef STRUCT
210#define STRUCT struct SRegisters
211
212static FreezeData SnapRegisters[] =
213{
214 INT_ENTRY(6, PB),
215 INT_ENTRY(6, DB),
216 INT_ENTRY(6, P.W),
217 INT_ENTRY(6, A.W),
218 INT_ENTRY(6, D.W),
219 INT_ENTRY(6, S.W),
220 INT_ENTRY(6, X.W),
221 INT_ENTRY(6, Y.W),
222 INT_ENTRY(6, PCw)
223};
224
225#undef STRUCT
226#define STRUCT struct SPPU
227
228static FreezeData SnapPPU[] =
229{
230 INT_ENTRY(6, VMA.High),
231 INT_ENTRY(6, VMA.Increment),
232 INT_ENTRY(6, VMA.Address),
233 INT_ENTRY(6, VMA.Mask1),
234 INT_ENTRY(6, VMA.FullGraphicCount),
235 INT_ENTRY(6, VMA.Shift),
236 INT_ENTRY(6, WRAM),
237#define O(N) \
238 INT_ENTRY(6, BG[N].SCBase), \
239 INT_ENTRY(6, BG[N].HOffset), \
240 INT_ENTRY(6, BG[N].VOffset), \
241 INT_ENTRY(6, BG[N].BGSize), \
242 INT_ENTRY(6, BG[N].NameBase), \
243 INT_ENTRY(6, BG[N].SCSize)
244 O(0), O(1), O(2), O(3),
245#undef O
246 INT_ENTRY(6, BGMode),
247 INT_ENTRY(6, BG3Priority),
248 INT_ENTRY(6, CGFLIP),
249 INT_ENTRY(6, CGFLIPRead),
250 INT_ENTRY(6, CGADD),
251 INT_ENTRY(11, CGSavedByte),
252 ARRAY_ENTRY(6, CGDATA, 256, uint16_ARRAY_V),
253#define O(N) \
254 INT_ENTRY(6, OBJ[N].HPos), \
255 INT_ENTRY(6, OBJ[N].VPos), \
256 INT_ENTRY(6, OBJ[N].HFlip), \
257 INT_ENTRY(6, OBJ[N].VFlip), \
258 INT_ENTRY(6, OBJ[N].Name), \
259 INT_ENTRY(6, OBJ[N].Priority), \
260 INT_ENTRY(6, OBJ[N].Palette), \
261 INT_ENTRY(6, OBJ[N].Size)
262 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
263 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
264 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
265 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
266 O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39),
267 O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47),
268 O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55),
269 O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63),
270 O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71),
271 O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79),
272 O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87),
273 O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95),
274 O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103),
275 O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111),
276 O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119),
277 O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127),
278#undef O
279 INT_ENTRY(6, OBJThroughMain),
280 INT_ENTRY(6, OBJThroughSub),
281 INT_ENTRY(6, OBJAddition),
282 INT_ENTRY(6, OBJNameBase),
283 INT_ENTRY(6, OBJNameSelect),
284 INT_ENTRY(6, OBJSizeSelect),
285 INT_ENTRY(6, OAMAddr),
286 INT_ENTRY(6, SavedOAMAddr),
287 INT_ENTRY(6, OAMPriorityRotation),
288 INT_ENTRY(6, OAMFlip),
289 INT_ENTRY(6, OAMReadFlip),
290 INT_ENTRY(6, OAMTileAddress),
291 INT_ENTRY(6, OAMWriteRegister),
292 ARRAY_ENTRY(6, OAMData, 512 + 32, uint8_ARRAY_V),
293 INT_ENTRY(6, FirstSprite),
294 INT_ENTRY(6, LastSprite),
295 INT_ENTRY(6, HTimerEnabled),
296 INT_ENTRY(6, VTimerEnabled),
297 INT_ENTRY(6, HTimerPosition),
298 INT_ENTRY(6, VTimerPosition),
299 INT_ENTRY(6, IRQHBeamPos),
300 INT_ENTRY(6, IRQVBeamPos),
301 INT_ENTRY(6, HBeamFlip),
302 INT_ENTRY(6, VBeamFlip),
303 INT_ENTRY(6, HBeamPosLatched),
304 INT_ENTRY(6, VBeamPosLatched),
305 INT_ENTRY(6, GunHLatch),
306 INT_ENTRY(6, GunVLatch),
307 INT_ENTRY(6, HVBeamCounterLatched),
308 INT_ENTRY(6, Mode7HFlip),
309 INT_ENTRY(6, Mode7VFlip),
310 INT_ENTRY(6, Mode7Repeat),
311 INT_ENTRY(6, MatrixA),
312 INT_ENTRY(6, MatrixB),
313 INT_ENTRY(6, MatrixC),
314 INT_ENTRY(6, MatrixD),
315 INT_ENTRY(6, CentreX),
316 INT_ENTRY(6, CentreY),
317 INT_ENTRY(6, M7HOFS),
318 INT_ENTRY(6, M7VOFS),
319 INT_ENTRY(6, Mosaic),
320 INT_ENTRY(6, MosaicStart),
321 ARRAY_ENTRY(6, BGMosaic, 4, uint8_ARRAY_V),
322 INT_ENTRY(6, Window1Left),
323 INT_ENTRY(6, Window1Right),
324 INT_ENTRY(6, Window2Left),
325 INT_ENTRY(6, Window2Right),
326 INT_ENTRY(6, RecomputeClipWindows),
327#define O(N) \
328 INT_ENTRY(6, ClipCounts[N]), \
329 INT_ENTRY(6, ClipWindowOverlapLogic[N]), \
330 INT_ENTRY(6, ClipWindow1Enable[N]), \
331 INT_ENTRY(6, ClipWindow2Enable[N]), \
332 INT_ENTRY(6, ClipWindow1Inside[N]), \
333 INT_ENTRY(6, ClipWindow2Inside[N])
334 O(0), O(1), O(2), O(3), O(4), O(5),
335#undef O
336 INT_ENTRY(6, ForcedBlanking),
337 INT_ENTRY(6, FixedColourRed),
338 INT_ENTRY(6, FixedColourGreen),
339 INT_ENTRY(6, FixedColourBlue),
340 INT_ENTRY(6, Brightness),
341 INT_ENTRY(6, ScreenHeight),
342 INT_ENTRY(6, Need16x8Mulitply),
343 INT_ENTRY(6, BGnxOFSbyte),
344 INT_ENTRY(6, M7byte),
345 INT_ENTRY(6, HDMA),
346 INT_ENTRY(6, HDMAEnded),
347 INT_ENTRY(6, OpenBus1),
348 INT_ENTRY(6, OpenBus2),
349 INT_ENTRY(11, VRAMReadBuffer)
350};
351
352#undef STRUCT
353#define STRUCT struct SDMASnapshot
354
355static FreezeData SnapDMA[] =
356{
357#define O(N) \
358 INT_ENTRY(6, dma[N].ReverseTransfer), \
359 INT_ENTRY(6, dma[N].HDMAIndirectAddressing), \
360 INT_ENTRY(6, dma[N].UnusedBit43x0), \
361 INT_ENTRY(6, dma[N].AAddressFixed), \
362 INT_ENTRY(6, dma[N].AAddressDecrement), \
363 INT_ENTRY(6, dma[N].TransferMode), \
364 INT_ENTRY(6, dma[N].BAddress), \
365 INT_ENTRY(6, dma[N].AAddress), \
366 INT_ENTRY(6, dma[N].ABank), \
367 INT_ENTRY(6, dma[N].DMACount_Or_HDMAIndirectAddress), \
368 INT_ENTRY(6, dma[N].IndirectBank), \
369 INT_ENTRY(6, dma[N].Address), \
370 INT_ENTRY(6, dma[N].Repeat), \
371 INT_ENTRY(6, dma[N].LineCount), \
372 INT_ENTRY(6, dma[N].UnknownByte), \
373 INT_ENTRY(6, dma[N].DoTransfer)
374 O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7)
375#undef O
376};
377
378#undef STRUCT
379#define STRUCT struct SControlSnapshot
380
381static FreezeData SnapControls[] =
382{
383 INT_ENTRY(6, ver),
384 ARRAY_ENTRY(6, port1_read_idx, 2, uint8_ARRAY_V),
385 ARRAY_ENTRY(6, dummy1, 4, uint8_ARRAY_V),
386 ARRAY_ENTRY(6, port2_read_idx, 2, uint8_ARRAY_V),
387 ARRAY_ENTRY(6, dummy2, 4, uint8_ARRAY_V),
388 ARRAY_ENTRY(6, mouse_speed, 2, uint8_ARRAY_V),
389 INT_ENTRY(6, justifier_select),
390 ARRAY_ENTRY(6, dummy3, 8, uint8_ARRAY_V),
391 INT_ENTRY(6, pad_read),
392 INT_ENTRY(6, pad_read_last),
393 ARRAY_ENTRY(6, internal, 60, uint8_ARRAY_V),
394 ARRAY_ENTRY(10, internal_macs, 5, uint8_ARRAY_V)
395};
396
397#undef STRUCT
398#define STRUCT struct STimings
399
400static FreezeData SnapTimings[] =
401{
402 INT_ENTRY(6, H_Max_Master),
403 INT_ENTRY(6, H_Max),
404 INT_ENTRY(6, V_Max_Master),
405 INT_ENTRY(6, V_Max),
406 INT_ENTRY(6, HBlankStart),
407 INT_ENTRY(6, HBlankEnd),
408 INT_ENTRY(6, HDMAInit),
409 INT_ENTRY(6, HDMAStart),
410 INT_ENTRY(6, NMITriggerPos),
411 INT_ENTRY(6, WRAMRefreshPos),
412 INT_ENTRY(6, RenderPos),
413 INT_ENTRY(6, InterlaceField),
414 INT_ENTRY(6, DMACPUSync),
415 INT_ENTRY(6, NMIDMADelay),
416 INT_ENTRY(6, IRQFlagChanging),
417 INT_ENTRY(6, APUSpeedup),
418 INT_ENTRY(7, IRQTriggerCycles),
419 INT_ENTRY(7, APUAllowTimeOverflow),
420 INT_ENTRY(11, NextIRQTimer)
421};
422
423#undef STRUCT
424#define STRUCT struct FxRegs_s
425
426static FreezeData SnapFX[] =
427{
428 ARRAY_ENTRY(6, avReg, 16, uint32_ARRAY_V),
429 INT_ENTRY(6, vColorReg),
430 INT_ENTRY(6, vPlotOptionReg),
431 INT_ENTRY(6, vStatusReg),
432 INT_ENTRY(6, vPrgBankReg),
433 INT_ENTRY(6, vRomBankReg),
434 INT_ENTRY(6, vRamBankReg),
435 INT_ENTRY(6, vCacheBaseReg),
436 INT_ENTRY(6, vCacheFlags),
437 INT_ENTRY(6, vLastRamAdr),
438 POINTER_ENTRY(6, pvDreg, avRegAddr),
439 POINTER_ENTRY(6, pvSreg, avRegAddr),
440 INT_ENTRY(6, vRomBuffer),
441 INT_ENTRY(6, vPipe),
442 INT_ENTRY(6, vPipeAdr),
443 INT_ENTRY(6, vSign),
444 INT_ENTRY(6, vZero),
445 INT_ENTRY(6, vCarry),
446 INT_ENTRY(6, vOverflow),
447 INT_ENTRY(6, vErrorCode),
448 INT_ENTRY(6, vIllegalAddress),
449 INT_ENTRY(6, bBreakPoint),
450 INT_ENTRY(6, vBreakPoint),
451 INT_ENTRY(6, vStepPoint),
452 INT_ENTRY(6, nRamBanks),
453 INT_ENTRY(6, nRomBanks),
454 INT_ENTRY(6, vMode),
455 INT_ENTRY(6, vPrevMode),
456 POINTER_ENTRY(6, pvScreenBase, pvRam),
457#define O(N) \
458 POINTER_ENTRY(6, apvScreen[N], pvRam)
459 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
460 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
461 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
462 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31),
463#undef O
464 ARRAY_ENTRY(6, x, 32, uint32_ARRAY_V),
465 INT_ENTRY(6, vScreenHeight),
466 INT_ENTRY(6, vScreenRealHeight),
467 INT_ENTRY(6, vPrevScreenHeight),
468 INT_ENTRY(6, vScreenSize),
469 POINTER_ENTRY(6, pvRamBank, apvRamBank),
470 POINTER_ENTRY(6, pvRomBank, apvRomBank),
471 POINTER_ENTRY(6, pvPrgBank, apvRomBank),
472#define O(N) \
473 POINTER_ENTRY(6, apvRamBank[N], pvRam)
474 O(0), O(1), O(2), O(3),
475#undef O
476 INT_ENTRY(6, bCacheActive),
477 POINTER_ENTRY(6, pvCache, pvRegisters),
478 ARRAY_ENTRY(6, avCacheBackup, 512, uint8_ARRAY_V),
479 INT_ENTRY(6, vCounter),
480 INT_ENTRY(6, vInstCount),
481 INT_ENTRY(6, vSCBRDirty)
482};
483
484#undef STRUCT
485#define STRUCT struct SSA1
486
487static FreezeData SnapSA1[] =
488{
489 DELETED_INT_ENTRY(6, 7, CPUExecuting, 1),
490 INT_ENTRY(6, ShiftedPB),
491 INT_ENTRY(6, ShiftedDB),
492 INT_ENTRY(6, Flags),
493 DELETED_INT_ENTRY(6, 7, IRQActive, 1),
494 DELETED_INT_ENTRY(6, 7, Waiting, 1),
495 INT_ENTRY(6, WaitingForInterrupt),
496 DELETED_INT_ENTRY(6, 7, WaitAddress, 4),
497 DELETED_INT_ENTRY(6, 7, WaitCounter, 4),
498 DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4),
499 DELETED_INT_ENTRY(6, 7, Executing, 1),
500 INT_ENTRY(6, overflow),
501 INT_ENTRY(6, in_char_dma),
502 INT_ENTRY(6, op1),
503 INT_ENTRY(6, op2),
504 INT_ENTRY(6, arithmetic_op),
505 INT_ENTRY(6, sum),
506 INT_ENTRY(6, VirtualBitmapFormat),
507 INT_ENTRY(6, variable_bit_pos),
508 INT_ENTRY(7, Cycles),
509 INT_ENTRY(7, PrevCycles),
510 INT_ENTRY(7, TimerIRQLastState),
511 INT_ENTRY(7, HTimerIRQPos),
512 INT_ENTRY(7, VTimerIRQPos),
513 INT_ENTRY(7, HCounter),
514 INT_ENTRY(7, VCounter),
515 INT_ENTRY(7, PrevHCounter),
516 INT_ENTRY(7, MemSpeed),
517 INT_ENTRY(7, MemSpeedx2)
518};
519
520#undef STRUCT
521#define STRUCT struct SSA1Registers
522
523static FreezeData SnapSA1Registers[] =
524{
525 INT_ENTRY(6, PB),
526 INT_ENTRY(6, DB),
527 INT_ENTRY(6, P.W),
528 INT_ENTRY(6, A.W),
529 INT_ENTRY(6, D.W),
530 INT_ENTRY(6, S.W),
531 INT_ENTRY(6, X.W),
532 INT_ENTRY(6, Y.W),
533 INT_ENTRY(6, PCw)
534};
535
536#undef STRUCT
537#define STRUCT struct SDSP1
538
539static FreezeData SnapDSP1[] =
540{
541 INT_ENTRY(6, waiting4command),
542 INT_ENTRY(6, first_parameter),
543 INT_ENTRY(6, command),
544 INT_ENTRY(6, in_count),
545 INT_ENTRY(6, in_index),
546 INT_ENTRY(6, out_count),
547 INT_ENTRY(6, out_index),
548 ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V),
549 ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V),
550 INT_ENTRY(6, CentreX),
551 INT_ENTRY(6, CentreY),
552 INT_ENTRY(6, VOffset),
553 INT_ENTRY(6, VPlane_C),
554 INT_ENTRY(6, VPlane_E),
555 INT_ENTRY(6, SinAas),
556 INT_ENTRY(6, CosAas),
557 INT_ENTRY(6, SinAzs),
558 INT_ENTRY(6, CosAzs),
559 INT_ENTRY(6, SinAZS),
560 INT_ENTRY(6, CosAZS),
561 INT_ENTRY(6, SecAZS_C1),
562 INT_ENTRY(6, SecAZS_E1),
563 INT_ENTRY(6, SecAZS_C2),
564 INT_ENTRY(6, SecAZS_E2),
565 INT_ENTRY(6, Nx),
566 INT_ENTRY(6, Ny),
567 INT_ENTRY(6, Nz),
568 INT_ENTRY(6, Gx),
569 INT_ENTRY(6, Gy),
570 INT_ENTRY(6, Gz),
571 INT_ENTRY(6, C_Les),
572 INT_ENTRY(6, E_Les),
573 INT_ENTRY(6, G_Les),
574#define O(N) \
575 ARRAY_ENTRY(6, matrixA[N], 3, uint16_ARRAY_V), \
576 ARRAY_ENTRY(6, matrixB[N], 3, uint16_ARRAY_V), \
577 ARRAY_ENTRY(6, matrixC[N], 3, uint16_ARRAY_V)
578 O(0), O(1), O(2),
579#undef O
580 INT_ENTRY(6, Op00Multiplicand),
581 INT_ENTRY(6, Op00Multiplier),
582 INT_ENTRY(6, Op00Result),
583 INT_ENTRY(6, Op20Multiplicand),
584 INT_ENTRY(6, Op20Multiplier),
585 INT_ENTRY(6, Op20Result),
586 INT_ENTRY(6, Op10Coefficient),
587 INT_ENTRY(6, Op10Exponent),
588 INT_ENTRY(6, Op10CoefficientR),
589 INT_ENTRY(6, Op10ExponentR),
590 INT_ENTRY(6, Op04Angle),
591 INT_ENTRY(6, Op04Radius),
592 INT_ENTRY(6, Op04Sin),
593 INT_ENTRY(6, Op04Cos),
594 INT_ENTRY(6, Op0CA),
595 INT_ENTRY(6, Op0CX1),
596 INT_ENTRY(6, Op0CY1),
597 INT_ENTRY(6, Op0CX2),
598 INT_ENTRY(6, Op0CY2),
599 INT_ENTRY(6, Op02FX),
600 INT_ENTRY(6, Op02FY),
601 INT_ENTRY(6, Op02FZ),
602 INT_ENTRY(6, Op02LFE),
603 INT_ENTRY(6, Op02LES),
604 INT_ENTRY(6, Op02AAS),
605 INT_ENTRY(6, Op02AZS),
606 INT_ENTRY(6, Op02VOF),
607 INT_ENTRY(6, Op02VVA),
608 INT_ENTRY(6, Op02CX),
609 INT_ENTRY(6, Op02CY),
610 INT_ENTRY(6, Op0AVS),
611 INT_ENTRY(6, Op0AA),
612 INT_ENTRY(6, Op0AB),
613 INT_ENTRY(6, Op0AC),
614 INT_ENTRY(6, Op0AD),
615 INT_ENTRY(6, Op06X),
616 INT_ENTRY(6, Op06Y),
617 INT_ENTRY(6, Op06Z),
618 INT_ENTRY(6, Op06H),
619 INT_ENTRY(6, Op06V),
620 INT_ENTRY(6, Op06M),
621 INT_ENTRY(6, Op01m),
622 INT_ENTRY(6, Op01Zr),
623 INT_ENTRY(6, Op01Xr),
624 INT_ENTRY(6, Op01Yr),
625 INT_ENTRY(6, Op11m),
626 INT_ENTRY(6, Op11Zr),
627 INT_ENTRY(6, Op11Xr),
628 INT_ENTRY(6, Op11Yr),
629 INT_ENTRY(6, Op21m),
630 INT_ENTRY(6, Op21Zr),
631 INT_ENTRY(6, Op21Xr),
632 INT_ENTRY(6, Op21Yr),
633 INT_ENTRY(6, Op0DX),
634 INT_ENTRY(6, Op0DY),
635 INT_ENTRY(6, Op0DZ),
636 INT_ENTRY(6, Op0DF),
637 INT_ENTRY(6, Op0DL),
638 INT_ENTRY(6, Op0DU),
639 INT_ENTRY(6, Op1DX),
640 INT_ENTRY(6, Op1DY),
641 INT_ENTRY(6, Op1DZ),
642 INT_ENTRY(6, Op1DF),
643 INT_ENTRY(6, Op1DL),
644 INT_ENTRY(6, Op1DU),
645 INT_ENTRY(6, Op2DX),
646 INT_ENTRY(6, Op2DY),
647 INT_ENTRY(6, Op2DZ),
648 INT_ENTRY(6, Op2DF),
649 INT_ENTRY(6, Op2DL),
650 INT_ENTRY(6, Op2DU),
651 INT_ENTRY(6, Op03F),
652 INT_ENTRY(6, Op03L),
653 INT_ENTRY(6, Op03U),
654 INT_ENTRY(6, Op03X),
655 INT_ENTRY(6, Op03Y),
656 INT_ENTRY(6, Op03Z),
657 INT_ENTRY(6, Op13F),
658 INT_ENTRY(6, Op13L),
659 INT_ENTRY(6, Op13U),
660 INT_ENTRY(6, Op13X),
661 INT_ENTRY(6, Op13Y),
662 INT_ENTRY(6, Op13Z),
663 INT_ENTRY(6, Op23F),
664 INT_ENTRY(6, Op23L),
665 INT_ENTRY(6, Op23U),
666 INT_ENTRY(6, Op23X),
667 INT_ENTRY(6, Op23Y),
668 INT_ENTRY(6, Op23Z),
669 INT_ENTRY(6, Op14Zr),
670 INT_ENTRY(6, Op14Xr),
671 INT_ENTRY(6, Op14Yr),
672 INT_ENTRY(6, Op14U),
673 INT_ENTRY(6, Op14F),
674 INT_ENTRY(6, Op14L),
675 INT_ENTRY(6, Op14Zrr),
676 INT_ENTRY(6, Op14Xrr),
677 INT_ENTRY(6, Op14Yrr),
678 INT_ENTRY(6, Op0EH),
679 INT_ENTRY(6, Op0EV),
680 INT_ENTRY(6, Op0EX),
681 INT_ENTRY(6, Op0EY),
682 INT_ENTRY(6, Op0BX),
683 INT_ENTRY(6, Op0BY),
684 INT_ENTRY(6, Op0BZ),
685 INT_ENTRY(6, Op0BS),
686 INT_ENTRY(6, Op1BX),
687 INT_ENTRY(6, Op1BY),
688 INT_ENTRY(6, Op1BZ),
689 INT_ENTRY(6, Op1BS),
690 INT_ENTRY(6, Op2BX),
691 INT_ENTRY(6, Op2BY),
692 INT_ENTRY(6, Op2BZ),
693 INT_ENTRY(6, Op2BS),
694 INT_ENTRY(6, Op28X),
695 INT_ENTRY(6, Op28Y),
696 INT_ENTRY(6, Op28Z),
697 INT_ENTRY(6, Op28R),
698 INT_ENTRY(6, Op1CX),
699 INT_ENTRY(6, Op1CY),
700 INT_ENTRY(6, Op1CZ),
701 INT_ENTRY(6, Op1CXBR),
702 INT_ENTRY(6, Op1CYBR),
703 INT_ENTRY(6, Op1CZBR),
704 INT_ENTRY(6, Op1CXAR),
705 INT_ENTRY(6, Op1CYAR),
706 INT_ENTRY(6, Op1CZAR),
707 INT_ENTRY(6, Op1CX1),
708 INT_ENTRY(6, Op1CY1),
709 INT_ENTRY(6, Op1CZ1),
710 INT_ENTRY(6, Op1CX2),
711 INT_ENTRY(6, Op1CY2),
712 INT_ENTRY(6, Op1CZ2),
713 INT_ENTRY(6, Op0FRamsize),
714 INT_ENTRY(6, Op0FPass),
715 INT_ENTRY(6, Op2FUnknown),
716 INT_ENTRY(6, Op2FSize),
717 INT_ENTRY(6, Op08X),
718 INT_ENTRY(6, Op08Y),
719 INT_ENTRY(6, Op08Z),
720 INT_ENTRY(6, Op08Ll),
721 INT_ENTRY(6, Op08Lh),
722 INT_ENTRY(6, Op18X),
723 INT_ENTRY(6, Op18Y),
724 INT_ENTRY(6, Op18Z),
725 INT_ENTRY(6, Op18R),
726 INT_ENTRY(6, Op18D),
727 INT_ENTRY(6, Op38X),
728 INT_ENTRY(6, Op38Y),
729 INT_ENTRY(6, Op38Z),
730 INT_ENTRY(6, Op38R),
731 INT_ENTRY(6, Op38D)
732};
733
734#undef STRUCT
735#define STRUCT struct SDSP2
736
737static FreezeData SnapDSP2[] =
738{
739 INT_ENTRY(6, waiting4command),
740 INT_ENTRY(6, command),
741 INT_ENTRY(6, in_count),
742 INT_ENTRY(6, in_index),
743 INT_ENTRY(6, out_count),
744 INT_ENTRY(6, out_index),
745 ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V),
746 ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V),
747 INT_ENTRY(6, Op05HasLen),
748 INT_ENTRY(6, Op05Len),
749 INT_ENTRY(6, Op05Transparent),
750 INT_ENTRY(6, Op06HasLen),
751 INT_ENTRY(6, Op06Len),
752 INT_ENTRY(6, Op09Word1),
753 INT_ENTRY(6, Op09Word2),
754 INT_ENTRY(6, Op0DHasLen),
755 INT_ENTRY(6, Op0DOutLen),
756 INT_ENTRY(6, Op0DInLen)
757};
758
759#undef STRUCT
760#define STRUCT struct SDSP4
761
762static FreezeData SnapDSP4[] =
763{
764 INT_ENTRY(6, waiting4command),
765 INT_ENTRY(6, half_command),
766 INT_ENTRY(6, command),
767 INT_ENTRY(6, in_count),
768 INT_ENTRY(6, in_index),
769 INT_ENTRY(6, out_count),
770 INT_ENTRY(6, out_index),
771 ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V),
772 ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V),
773 INT_ENTRY(6, byte),
774 INT_ENTRY(6, address),
775 INT_ENTRY(6, Logic),
776 INT_ENTRY(6, lcv),
777 INT_ENTRY(6, distance),
778 INT_ENTRY(6, raster),
779 INT_ENTRY(6, segments),
780 INT_ENTRY(6, world_x),
781 INT_ENTRY(6, world_y),
782 INT_ENTRY(6, world_dx),
783 INT_ENTRY(6, world_dy),
784 INT_ENTRY(6, world_ddx),
785 INT_ENTRY(6, world_ddy),
786 INT_ENTRY(6, world_xenv),
787 INT_ENTRY(6, world_yofs),
788 INT_ENTRY(6, view_x1),
789 INT_ENTRY(6, view_y1),
790 INT_ENTRY(6, view_x2),
791 INT_ENTRY(6, view_y2),
792 INT_ENTRY(6, view_dx),
793 INT_ENTRY(6, view_dy),
794 INT_ENTRY(6, view_xofs1),
795 INT_ENTRY(6, view_yofs1),
796 INT_ENTRY(6, view_xofs2),
797 INT_ENTRY(6, view_yofs2),
798 INT_ENTRY(6, view_yofsenv),
799 INT_ENTRY(6, view_turnoff_x),
800 INT_ENTRY(6, view_turnoff_dx),
801 INT_ENTRY(6, viewport_cx),
802 INT_ENTRY(6, viewport_cy),
803 INT_ENTRY(6, viewport_left),
804 INT_ENTRY(6, viewport_right),
805 INT_ENTRY(6, viewport_top),
806 INT_ENTRY(6, viewport_bottom),
807 INT_ENTRY(6, sprite_x),
808 INT_ENTRY(6, sprite_y),
809 INT_ENTRY(6, sprite_attr),
810 INT_ENTRY(6, sprite_size),
811 INT_ENTRY(6, sprite_clipy),
812 INT_ENTRY(6, sprite_count),
813#define O(N) \
814 ARRAY_ENTRY(6, poly_clipLf[N], 2, uint16_ARRAY_V), \
815 ARRAY_ENTRY(6, poly_clipRt[N], 2, uint16_ARRAY_V), \
816 ARRAY_ENTRY(6, poly_ptr[N], 2, uint16_ARRAY_V), \
817 ARRAY_ENTRY(6, poly_raster[N], 2, uint16_ARRAY_V), \
818 ARRAY_ENTRY(6, poly_top[N], 2, uint16_ARRAY_V), \
819 ARRAY_ENTRY(6, poly_bottom[N], 2, uint16_ARRAY_V), \
820 ARRAY_ENTRY(6, poly_cx[N], 2, uint16_ARRAY_V)
821 O(0), O(1),
822#undef O
823 ARRAY_ENTRY(6, poly_start, 2, uint16_ARRAY_V),
824 ARRAY_ENTRY(6, poly_plane, 2, uint16_ARRAY_V),
825 ARRAY_ENTRY(6, OAM_attr, 16, uint16_ARRAY_V),
826 INT_ENTRY(6, OAM_index),
827 INT_ENTRY(6, OAM_bits),
828 INT_ENTRY(6, OAM_RowMax),
829 ARRAY_ENTRY(6, OAM_Row, 32, uint16_ARRAY_V)
830};
831
832#undef STRUCT
833#define STRUCT struct SST010
834
835static FreezeData SnapST010[] =
836{
837 ARRAY_ENTRY(6, input_params, 16, uint8_ARRAY_V),
838 ARRAY_ENTRY(6, output_params, 16, uint8_ARRAY_V),
839 INT_ENTRY(6, op_reg),
840 INT_ENTRY(6, execute),
841 INT_ENTRY(6, control_enable)
842};
843
844#undef STRUCT
845#define STRUCT struct SOBC1
846
847static FreezeData SnapOBC1[] =
848{
849 INT_ENTRY(6, address),
850 INT_ENTRY(6, basePtr),
851 INT_ENTRY(6, shift)
852};
853
854#undef STRUCT
855#define STRUCT struct SSPC7110Snapshot
856
857static FreezeData SnapSPC7110Snap[] =
858{
859 INT_ENTRY(6, r4801),
860 INT_ENTRY(6, r4802),
861 INT_ENTRY(6, r4803),
862 INT_ENTRY(6, r4804),
863 INT_ENTRY(6, r4805),
864 INT_ENTRY(6, r4806),
865 INT_ENTRY(6, r4807),
866 INT_ENTRY(6, r4808),
867 INT_ENTRY(6, r4809),
868 INT_ENTRY(6, r480a),
869 INT_ENTRY(6, r480b),
870 INT_ENTRY(6, r480c),
871 INT_ENTRY(6, r4811),
872 INT_ENTRY(6, r4812),
873 INT_ENTRY(6, r4813),
874 INT_ENTRY(6, r4814),
875 INT_ENTRY(6, r4815),
876 INT_ENTRY(6, r4816),
877 INT_ENTRY(6, r4817),
878 INT_ENTRY(6, r4818),
879 INT_ENTRY(6, r481x),
880 INT_ENTRY(6, r4814_latch),
881 INT_ENTRY(6, r4815_latch),
882 INT_ENTRY(6, r4820),
883 INT_ENTRY(6, r4821),
884 INT_ENTRY(6, r4822),
885 INT_ENTRY(6, r4823),
886 INT_ENTRY(6, r4824),
887 INT_ENTRY(6, r4825),
888 INT_ENTRY(6, r4826),
889 INT_ENTRY(6, r4827),
890 INT_ENTRY(6, r4828),
891 INT_ENTRY(6, r4829),
892 INT_ENTRY(6, r482a),
893 INT_ENTRY(6, r482b),
894 INT_ENTRY(6, r482c),
895 INT_ENTRY(6, r482d),
896 INT_ENTRY(6, r482e),
897 INT_ENTRY(6, r482f),
898 INT_ENTRY(6, r4830),
899 INT_ENTRY(6, r4831),
900 INT_ENTRY(6, r4832),
901 INT_ENTRY(6, r4833),
902 INT_ENTRY(6, r4834),
903 INT_ENTRY(6, dx_offset),
904 INT_ENTRY(6, ex_offset),
905 INT_ENTRY(6, fx_offset),
906 INT_ENTRY(6, r4840),
907 INT_ENTRY(6, r4841),
908 INT_ENTRY(6, r4842),
909 INT_ENTRY(6, rtc_state),
910 INT_ENTRY(6, rtc_mode),
911 INT_ENTRY(6, rtc_index),
912 INT_ENTRY(6, decomp_mode),
913 INT_ENTRY(6, decomp_offset),
914 ARRAY_ENTRY(6, decomp_buffer, SPC7110_DECOMP_BUFFER_SIZE, uint8_ARRAY_V),
915 INT_ENTRY(6, decomp_buffer_rdoffset),
916 INT_ENTRY(6, decomp_buffer_wroffset),
917 INT_ENTRY(6, decomp_buffer_length),
918#define O(N) \
919 INT_ENTRY(6, context[N].index), \
920 INT_ENTRY(6, context[N].invert)
921 O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7),
922 O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15),
923 O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23),
924 O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31)
925#undef O
926};
927
928#undef STRUCT
929#define STRUCT struct SSRTCSnapshot
930
931static FreezeData SnapSRTCSnap[] =
932{
933 INT_ENTRY(6, rtc_mode),
934 INT_ENTRY(6, rtc_index)
935};
936
937#undef STRUCT
938#define STRUCT struct SBSX
939
940static FreezeData SnapBSX[] =
941{
942 INT_ENTRY(6, dirty),
943 INT_ENTRY(6, dirty2),
944 INT_ENTRY(6, bootup),
945 INT_ENTRY(6, flash_enable),
946 INT_ENTRY(6, write_enable),
947 INT_ENTRY(6, read_enable),
948 INT_ENTRY(6, flash_command),
949 INT_ENTRY(6, old_write),
950 INT_ENTRY(6, new_write),
951 INT_ENTRY(6, out_index),
952 ARRAY_ENTRY(6, output, 32, uint8_ARRAY_V),
953 ARRAY_ENTRY(6, PPU, 32, uint8_ARRAY_V),
954 ARRAY_ENTRY(6, MMC, 16, uint8_ARRAY_V),
955 ARRAY_ENTRY(6, prevMMC, 16, uint8_ARRAY_V),
956 ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V)
957};
958
959#undef STRUCT
960#define STRUCT struct SMSU1
961
962static FreezeData SnapMSU1[] =
963{
964 INT_ENTRY(9, MSU1_STATUS),
965 INT_ENTRY(9, MSU1_DATA_SEEK),
966 INT_ENTRY(9, MSU1_DATA_POS),
967 INT_ENTRY(9, MSU1_TRACK_SEEK),
968 INT_ENTRY(9, MSU1_CURRENT_TRACK),
969 INT_ENTRY(9, MSU1_RESUME_TRACK),
970 INT_ENTRY(9, MSU1_VOLUME),
971 INT_ENTRY(9, MSU1_CONTROL),
972 INT_ENTRY(9, MSU1_AUDIO_POS),
973 INT_ENTRY(9, MSU1_RESUME_POS)
974};
975
976#undef STRUCT
977#define STRUCT struct SnapshotScreenshotInfo
978
979static FreezeData SnapScreenshot[] =
980{
981 INT_ENTRY(6, Width),
982 INT_ENTRY(6, Height),
983 INT_ENTRY(6, Interlaced),
984 ARRAY_ENTRY(6, Data, MAX_SNES_WIDTH * MAX_SNES_HEIGHT * 3, uint8_ARRAY_V)
985};
986
987#undef STRUCT
988#define STRUCT struct SnapshotMovieInfo
989
990static FreezeData SnapMovie[] =
991{
992 INT_ENTRY(6, MovieInputDataSize)
993};
994
995static int UnfreezeBlock (STREAM, const char *, uint8 *, int);
996static int UnfreezeBlockCopy (STREAM, const char *, uint8 **, int);
997static int UnfreezeStruct (STREAM, const char *, void *, FreezeData *, int, int);
998static int UnfreezeStructCopy (STREAM, const char *, uint8 **, FreezeData *, int, int);
999static void UnfreezeStructFromCopy (void *, FreezeData *, int, uint8 *, int);
1000static void FreezeBlock (STREAM, const char *, uint8 *, int);
1001static void FreezeStruct (STREAM, const char *, void *, FreezeData *, int);
1002static bool CheckBlockName(STREAM stream, const char *name, int &len);
1003static void SkipBlockWithName(STREAM stream, const char *name);
1004
1005
1006void S9xResetSaveTimer (bool8 dontsave)
1007{
1008 static time_t t = -1;
1009
1010 if (!Settings.DontSaveOopsSnapshot && !dontsave && t != -1 && time(NULL) - t > 300)
1011 {
1012 char filename[PATH_MAX + 1];
1013 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
1014
1015 _splitpath(Memory.ROMFilename, drive, dir, def, ext);
1016 snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
1017 S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, SAVE_INFO_OOPS);
1018 S9xFreezeGame(filename);
1019 }
1020
1021 t = time(NULL);
1022}
1023
1024uint32 S9xFreezeSize()
1025{
1026 nulStream stream;
1027 S9xFreezeToStream(&stream);
1028 return stream.size();
1029}
1030
1031bool8 S9xFreezeGameMem (uint8 *buf, uint32 bufSize)
1032{
1033 memStream mStream(buf, bufSize);
1034 S9xFreezeToStream(&mStream);
1035
1036 return (TRUE);
1037}
1038
1039bool8 S9xFreezeGame (const char *filename)
1040{
1041 STREAM stream = NULL;
1042
1043 if (S9xOpenSnapshotFile(filename, FALSE, &stream))
1044 {
1045 S9xFreezeToStream(stream);
1046 S9xCloseSnapshotFile(stream);
1047
1048 S9xResetSaveTimer(TRUE);
1049
1050 const char *base = S9xBasename(filename);
1051 if (S9xMovieActive())
1052 sprintf(String, MOVIE_INFO_SNAPSHOT " %s", base);
1053 else
1054 sprintf(String, SAVE_INFO_SNAPSHOT " %s", base);
1055
1056 S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
1057
1058 return (TRUE);
1059 }
1060
1061 return (FALSE);
1062}
1063
1064int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize)
1065{
1066 memStream stream(buf, bufSize);
1067 int result = S9xUnfreezeFromStream(&stream);
1068
1069 return result;
1070}
1071
1072bool8 S9xUnfreezeGame (const char *filename)
1073{
1074 STREAM stream = NULL;
1075 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
1076
1077 const char *base = S9xBasename(filename);
1078
1079 _splitpath(filename, drive, dir, def, ext);
1080 S9xResetSaveTimer(!strcmp(ext, "oops") || !strcmp(ext, "oop") || !strcmp(ext, ".oops") || !strcmp(ext, ".oop"));
1081
1082 if (S9xOpenSnapshotFile(filename, TRUE, &stream))
1083 {
1084 int result;
1085
1086 result = S9xUnfreezeFromStream(stream);
1087 S9xCloseSnapshotFile(stream);
1088
1089 if (result != SUCCESS)
1090 {
1091 switch (result)
1092 {
1093 case WRONG_FORMAT:
1094 S9xMessage(S9X_ERROR, S9X_WRONG_FORMAT, SAVE_ERR_WRONG_FORMAT);
1095 break;
1096
1097 case WRONG_VERSION:
1098 S9xMessage(S9X_ERROR, S9X_WRONG_VERSION, SAVE_ERR_WRONG_VERSION);
1099 break;
1100
1101 case WRONG_MOVIE_SNAPSHOT:
1102 S9xMessage(S9X_ERROR, S9X_WRONG_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_WRONG_MOVIE);
1103 break;
1104
1105 case NOT_A_MOVIE_SNAPSHOT:
1106 S9xMessage(S9X_ERROR, S9X_NOT_A_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_NOT_MOVIE);
1107 break;
1108
1109 case SNAPSHOT_INCONSISTENT:
1110 S9xMessage(S9X_ERROR, S9X_SNAPSHOT_INCONSISTENT, MOVIE_ERR_SNAPSHOT_INCONSISTENT);
1111 break;
1112
1113 case FILE_NOT_FOUND:
1114 default:
1115 sprintf(String, SAVE_ERR_ROM_NOT_FOUND, base);
1116 S9xMessage(S9X_ERROR, S9X_ROM_NOT_FOUND, String);
1117 break;
1118 }
1119
1120 return (FALSE);
1121 }
1122
1123 if (S9xMovieActive())
1124 {
1125 if (S9xMovieReadOnly())
1126 sprintf(String, MOVIE_INFO_REWIND " %s", base);
1127 else
1128 sprintf(String, MOVIE_INFO_RERECORD " %s", base);
1129 }
1130 else
1131 sprintf(String, SAVE_INFO_LOAD " %s", base);
1132
1133 S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
1134
1135 return (TRUE);
1136 }
1137
1138 sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base);
1139 S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
1140
1141 return (FALSE);
1142}
1143
1144void S9xFreezeToStream (STREAM stream)
1145{
1146 char buffer[8192];
1147 uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE];
1148
1149 sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
1150 WRITE_STREAM(buffer, strlen(buffer), stream);
1151
1152 sprintf(buffer, "NAM:%06d:%s%c", (int) strlen(Memory.ROMFilename) + 1, Memory.ROMFilename, 0);
1153 WRITE_STREAM(buffer, strlen(buffer) + 1, stream);
1154
1155 FreezeStruct(stream, "CPU", &CPU, SnapCPU, COUNT(SnapCPU));
1156
1157 FreezeStruct(stream, "REG", &Registers, SnapRegisters, COUNT(SnapRegisters));
1158
1159 FreezeStruct(stream, "PPU", &PPU, SnapPPU, COUNT(SnapPPU));
1160
1161 struct SDMASnapshot dma_snap;
1162 for (int d = 0; d < 8; d++)
1163 dma_snap.dma[d] = DMA[d];
1164 FreezeStruct(stream, "DMA", &dma_snap, SnapDMA, COUNT(SnapDMA));
1165
1166 FreezeBlock (stream, "VRA", Memory.VRAM, 0x10000);
1167
1168 FreezeBlock (stream, "RAM", Memory.RAM, 0x20000);
1169
1170 FreezeBlock (stream, "SRA", Memory.SRAM, 0x20000);
1171
1172 FreezeBlock (stream, "FIL", Memory.FillRAM, 0x8000);
1173
1174 S9xAPUSaveState(soundsnapshot);
1175 FreezeBlock (stream, "SND", soundsnapshot, SPC_SAVE_STATE_BLOCK_SIZE);
1176
1177 struct SControlSnapshot ctl_snap;
1178 S9xControlPreSaveState(&ctl_snap);
1179 FreezeStruct(stream, "CTL", &ctl_snap, SnapControls, COUNT(SnapControls));
1180
1181 FreezeStruct(stream, "TIM", &Timings, SnapTimings, COUNT(SnapTimings));
1182
1183 if (Settings.SuperFX)
1184 {
1185 GSU.avRegAddr = (uint8 *) &GSU.avReg;
1186 FreezeStruct(stream, "SFX", &GSU, SnapFX, COUNT(SnapFX));
1187 }
1188
1189 if (Settings.SA1)
1190 {
1191 S9xSA1PackStatus();
1192 FreezeStruct(stream, "SA1", &SA1, SnapSA1, COUNT(SnapSA1));
1193 FreezeStruct(stream, "SAR", &SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers));
1194 }
1195
1196 if (Settings.DSP == 1)
1197 FreezeStruct(stream, "DP1", &DSP1, SnapDSP1, COUNT(SnapDSP1));
1198
1199 if (Settings.DSP == 2)
1200 FreezeStruct(stream, "DP2", &DSP2, SnapDSP2, COUNT(SnapDSP2));
1201
1202 if (Settings.DSP == 4)
1203 FreezeStruct(stream, "DP4", &DSP4, SnapDSP4, COUNT(SnapDSP4));
1204
1205 if (Settings.C4)
1206 FreezeBlock (stream, "CX4", Memory.C4RAM, 8192);
1207
1208 if (Settings.SETA == ST_010)
1209 FreezeStruct(stream, "ST0", &ST010, SnapST010, COUNT(SnapST010));
1210
1211 if (Settings.OBC1)
1212 {
1213 FreezeStruct(stream, "OBC", &OBC1, SnapOBC1, COUNT(SnapOBC1));
1214 FreezeBlock (stream, "OBM", Memory.OBC1RAM, 8192);
1215 }
1216
1217 if (Settings.SPC7110)
1218 {
1219 S9xSPC7110PreSaveState();
1220 FreezeStruct(stream, "S71", &s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap));
1221 }
1222
1223 if (Settings.SRTC)
1224 {
1225 S9xSRTCPreSaveState();
1226 FreezeStruct(stream, "SRT", &srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap));
1227 }
1228
1229 if (Settings.SRTC || Settings.SPC7110RTC)
1230 FreezeBlock (stream, "CLK", RTCData.reg, 20);
1231
1232 if (Settings.BS)
1233 FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX));
1234
1235 if (Settings.MSU1)
1236 FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1));
1237
1238 if (Settings.SnapshotScreenshots)
1239 {
1240 SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo;
1241
1242 ssi->Width = min(IPPU.RenderedScreenWidth, MAX_SNES_WIDTH);
1243 ssi->Height = min(IPPU.RenderedScreenHeight, MAX_SNES_HEIGHT);
1244 ssi->Interlaced = GFX.DoInterlace;
1245
1246 uint8 *rowpix = ssi->Data;
1247 uint16 *screen = GFX.Screen;
1248
1249 for (int y = 0; y < ssi->Height; y++, screen += GFX.RealPPL)
1250 {
1251 for (int x = 0; x < ssi->Width; x++)
1252 {
1253 uint32 r, g, b;
1254
1255 DECOMPOSE_PIXEL(screen[x], r, g, b);
1256 *(rowpix++) = r;
1257 *(rowpix++) = g;
1258 *(rowpix++) = b;
1259 }
1260 }
1261
1262 memset(rowpix, 0, sizeof(ssi->Data) + ssi->Data - rowpix);
1263
1264 FreezeStruct(stream, "SHO", ssi, SnapScreenshot, COUNT(SnapScreenshot));
1265
1266 delete ssi;
1267 }
1268
1269 if (S9xMovieActive())
1270 {
1271 uint8 *movie_freeze_buf;
1272 uint32 movie_freeze_size;
1273
1274 S9xMovieFreeze(&movie_freeze_buf, &movie_freeze_size);
1275 if (movie_freeze_buf)
1276 {
1277 struct SnapshotMovieInfo mi;
1278
1279 mi.MovieInputDataSize = movie_freeze_size;
1280 FreezeStruct(stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie));
1281 FreezeBlock (stream, "MID", movie_freeze_buf, movie_freeze_size);
1282
1283 delete [] movie_freeze_buf;
1284 }
1285 }
1286
1287 delete [] soundsnapshot;
1288}
1289
1290int S9xUnfreezeFromStream (STREAM stream)
1291{
1292 const bool8 fast = Settings.FastSavestates;
1293
1294 int result = SUCCESS;
1295 int version, len;
1296 char buffer[PATH_MAX + 1];
1297
1298 len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1;
1299 if (READ_STREAM(buffer, len, stream) != (unsigned int ) len)
1300 return (WRONG_FORMAT);
1301
1302 if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0)
1303 return (WRONG_FORMAT);
1304
1305 version = atoi(&buffer[strlen(SNAPSHOT_MAGIC) + 1]);
1306 if (version > SNAPSHOT_VERSION)
1307 return (WRONG_VERSION);
1308
1309 result = UnfreezeBlock(stream, "NAM", (uint8 *) buffer, PATH_MAX);
1310 if (result != SUCCESS)
1311 return (result);
1312
1313 uint8 *local_cpu = NULL;
1314 uint8 *local_registers = NULL;
1315 uint8 *local_ppu = NULL;
1316 uint8 *local_dma = NULL;
1317 uint8 *local_vram = NULL;
1318 uint8 *local_ram = NULL;
1319 uint8 *local_sram = NULL;
1320 uint8 *local_fillram = NULL;
1321 uint8 *local_apu_sound = NULL;
1322 uint8 *local_control_data = NULL;
1323 uint8 *local_timing_data = NULL;
1324 uint8 *local_superfx = NULL;
1325 uint8 *local_sa1 = NULL;
1326 uint8 *local_sa1_registers = NULL;
1327 uint8 *local_dsp1 = NULL;
1328 uint8 *local_dsp2 = NULL;
1329 uint8 *local_dsp4 = NULL;
1330 uint8 *local_cx4_data = NULL;
1331 uint8 *local_st010 = NULL;
1332 uint8 *local_obc1 = NULL;
1333 uint8 *local_obc1_data = NULL;
1334 uint8 *local_spc7110 = NULL;
1335 uint8 *local_srtc = NULL;
1336 uint8 *local_rtc_data = NULL;
1337 uint8 *local_bsx_data = NULL;
1338 uint8 *local_msu1_data = NULL;
1339 uint8 *local_screenshot = NULL;
1340 uint8 *local_movie_data = NULL;
1341
1342 do
1343 {
1344 result = UnfreezeStructCopy(stream, "CPU", &local_cpu, SnapCPU, COUNT(SnapCPU), version);
1345 if (result != SUCCESS)
1346 break;
1347
1348 result = UnfreezeStructCopy(stream, "REG", &local_registers, SnapRegisters, COUNT(SnapRegisters), version);
1349 if (result != SUCCESS)
1350 break;
1351
1352 result = UnfreezeStructCopy(stream, "PPU", &local_ppu, SnapPPU, COUNT(SnapPPU), version);
1353 if (result != SUCCESS)
1354 break;
1355
1356 result = UnfreezeStructCopy(stream, "DMA", &local_dma, SnapDMA, COUNT(SnapDMA), version);
1357 if (result != SUCCESS)
1358 break;
1359
1360 if (fast)
1361 result = UnfreezeBlock(stream, "VRA", Memory.VRAM, 0x10000);
1362 else
1363 result = UnfreezeBlockCopy(stream, "VRA", &local_vram, 0x10000);
1364 if (result != SUCCESS)
1365 break;
1366
1367 if (fast)
1368 result = UnfreezeBlock(stream, "RAM", Memory.RAM, 0x20000);
1369 else
1370 result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000);
1371 if (result != SUCCESS)
1372 break;
1373
1374 if (fast)
1375 result = UnfreezeBlock(stream, "SRA", Memory.SRAM, 0x20000);
1376 else
1377 result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000);
1378 if (result != SUCCESS)
1379 break;
1380
1381 if (fast)
1382 result = UnfreezeBlock(stream, "FIL", Memory.FillRAM, 0x8000);
1383 else
1384 result = UnfreezeBlockCopy(stream, "FIL", &local_fillram, 0x8000);
1385 if (result != SUCCESS)
1386 break;
1387
1388 result = UnfreezeBlockCopy (stream, "SND", &local_apu_sound, SPC_SAVE_STATE_BLOCK_SIZE);
1389 if (result != SUCCESS)
1390 break;
1391
1392 result = UnfreezeStructCopy(stream, "CTL", &local_control_data, SnapControls, COUNT(SnapControls), version);
1393 if (result != SUCCESS)
1394 break;
1395
1396 result = UnfreezeStructCopy(stream, "TIM", &local_timing_data, SnapTimings, COUNT(SnapTimings), version);
1397 if (result != SUCCESS)
1398 break;
1399
1400 result = UnfreezeStructCopy(stream, "SFX", &local_superfx, SnapFX, COUNT(SnapFX), version);
1401 if (result != SUCCESS && Settings.SuperFX)
1402 break;
1403
1404 result = UnfreezeStructCopy(stream, "SA1", &local_sa1, SnapSA1, COUNT(SnapSA1), version);
1405 if (result != SUCCESS && Settings.SA1)
1406 break;
1407
1408 result = UnfreezeStructCopy(stream, "SAR", &local_sa1_registers, SnapSA1Registers, COUNT(SnapSA1Registers), version);
1409 if (result != SUCCESS && Settings.SA1)
1410 break;
1411
1412 result = UnfreezeStructCopy(stream, "DP1", &local_dsp1, SnapDSP1, COUNT(SnapDSP1), version);
1413 if (result != SUCCESS && Settings.DSP == 1)
1414 break;
1415
1416 result = UnfreezeStructCopy(stream, "DP2", &local_dsp2, SnapDSP2, COUNT(SnapDSP2), version);
1417 if (result != SUCCESS && Settings.DSP == 2)
1418 break;
1419
1420 result = UnfreezeStructCopy(stream, "DP4", &local_dsp4, SnapDSP4, COUNT(SnapDSP4), version);
1421 if (result != SUCCESS && Settings.DSP == 4)
1422 break;
1423
1424 if (Settings.C4)
1425 {
1426 if (fast)
1427 result = UnfreezeBlock(stream, "CX4", Memory.C4RAM, 8192);
1428 else
1429 result = UnfreezeBlockCopy(stream, "CX4", &local_cx4_data, 8192);
1430 if (result != SUCCESS)
1431 break;
1432 }
1433 else
1434 {
1435 SkipBlockWithName(stream, "CX4");
1436 }
1437
1438 result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version);
1439 if (result != SUCCESS && Settings.SETA == ST_010)
1440 break;
1441
1442 result = UnfreezeStructCopy(stream, "OBC", &local_obc1, SnapOBC1, COUNT(SnapOBC1), version);
1443 if (result != SUCCESS && Settings.OBC1)
1444 break;
1445
1446 if (Settings.OBC1)
1447 {
1448 if (fast)
1449 result = UnfreezeBlock(stream, "OBM", Memory.OBC1RAM, 8192);
1450 else
1451 result = UnfreezeBlockCopy(stream, "OBM", &local_obc1_data, 8192);
1452 if (result != SUCCESS)
1453 break;
1454 }
1455 else
1456 {
1457 SkipBlockWithName(stream, "OBM");
1458 }
1459
1460 result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version);
1461 if (result != SUCCESS && Settings.SPC7110)
1462 break;
1463
1464 result = UnfreezeStructCopy(stream, "SRT", &local_srtc, SnapSRTCSnap, COUNT(SnapSRTCSnap), version);
1465 if (result != SUCCESS && Settings.SRTC)
1466 break;
1467
1468 result = UnfreezeBlockCopy (stream, "CLK", &local_rtc_data, 20);
1469 if (result != SUCCESS && (Settings.SRTC || Settings.SPC7110RTC))
1470 break;
1471
1472 result = UnfreezeStructCopy(stream, "BSX", &local_bsx_data, SnapBSX, COUNT(SnapBSX), version);
1473 if (result != SUCCESS && Settings.BS)
1474 break;
1475
1476 result = UnfreezeStructCopy(stream, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version);
1477 if (result != SUCCESS && Settings.MSU1)
1478 break;
1479
1480 result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version);
1481
1482 SnapshotMovieInfo mi;
1483
1484 result = UnfreezeStruct(stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie), version);
1485 if (result != SUCCESS)
1486 {
1487 if (S9xMovieActive())
1488 {
1489 result = NOT_A_MOVIE_SNAPSHOT;
1490 break;
1491 }
1492 }
1493 else
1494 {
1495 result = UnfreezeBlockCopy(stream, "MID", &local_movie_data, mi.MovieInputDataSize);
1496 if (result != SUCCESS)
1497 {
1498 if (S9xMovieActive())
1499 {
1500 result = NOT_A_MOVIE_SNAPSHOT;
1501 break;
1502 }
1503 }
1504
1505 if (S9xMovieActive())
1506 {
1507 result = S9xMovieUnfreeze(local_movie_data, mi.MovieInputDataSize);
1508 if (result != SUCCESS)
1509 break;
1510 }
1511 }
1512
1513 result = SUCCESS;
1514 } while (false);
1515
1516 if (result == SUCCESS)
1517 {
1518 uint32 old_flags = CPU.Flags;
1519 uint32 sa1_old_flags = SA1.Flags;
1520
1521 if (fast)
1522 {
1523 S9xResetPPUFast();
1524 }
1525 else
1526 {
1527 //Do not call this if you have written directly to "Memory." arrays
1528 S9xReset();
1529 }
1530
1531 UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version);
1532
1533 UnfreezeStructFromCopy(&Registers, SnapRegisters, COUNT(SnapRegisters), local_registers, version);
1534
1535 UnfreezeStructFromCopy(&PPU, SnapPPU, COUNT(SnapPPU), local_ppu, version);
1536
1537 struct SDMASnapshot dma_snap;
1538 UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version);
1539
1540 if (local_vram)
1541 memcpy(Memory.VRAM, local_vram, 0x10000);
1542
1543 if (local_ram)
1544 memcpy(Memory.RAM, local_ram, 0x20000);
1545
1546 if (local_sram)
1547 memcpy(Memory.SRAM, local_sram, 0x20000);
1548
1549 if (local_fillram)
1550 memcpy(Memory.FillRAM, local_fillram, 0x8000);
1551
1552 if(version < SNAPSHOT_VERSION_BAPU) {
1553 printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION);
1554 S9xAPULoadBlarggState(local_apu_sound);
1555 } else
1556 S9xAPULoadState(local_apu_sound);
1557
1558 struct SControlSnapshot ctl_snap;
1559 UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version);
1560
1561 UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version);
1562
1563 if (local_superfx)
1564 {
1565 GSU.avRegAddr = (uint8 *) &GSU.avReg;
1566 UnfreezeStructFromCopy(&GSU, SnapFX, COUNT(SnapFX), local_superfx, version);
1567 }
1568
1569 if (local_sa1)
1570 UnfreezeStructFromCopy(&SA1, SnapSA1, COUNT(SnapSA1), local_sa1, version);
1571
1572 if (local_sa1_registers)
1573 UnfreezeStructFromCopy(&SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers), local_sa1_registers, version);
1574
1575 if (local_dsp1)
1576 UnfreezeStructFromCopy(&DSP1, SnapDSP1, COUNT(SnapDSP1), local_dsp1, version);
1577
1578 if (local_dsp2)
1579 UnfreezeStructFromCopy(&DSP2, SnapDSP2, COUNT(SnapDSP2), local_dsp2, version);
1580
1581 if (local_dsp4)
1582 UnfreezeStructFromCopy(&DSP4, SnapDSP4, COUNT(SnapDSP4), local_dsp4, version);
1583
1584 if (local_cx4_data)
1585 memcpy(Memory.C4RAM, local_cx4_data, 8192);
1586
1587 if (local_st010)
1588 UnfreezeStructFromCopy(&ST010, SnapST010, COUNT(SnapST010), local_st010, version);
1589
1590 if (local_obc1)
1591 UnfreezeStructFromCopy(&OBC1, SnapOBC1, COUNT(SnapOBC1), local_obc1, version);
1592
1593 if (local_obc1_data)
1594 memcpy(Memory.OBC1RAM, local_obc1_data, 8192);
1595
1596 if (local_spc7110)
1597 UnfreezeStructFromCopy(&s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), local_spc7110, version);
1598
1599 if (local_srtc)
1600 UnfreezeStructFromCopy(&srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap), local_srtc, version);
1601
1602 if (local_rtc_data)
1603 memcpy(RTCData.reg, local_rtc_data, 20);
1604
1605 if (local_bsx_data)
1606 UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version);
1607
1608 if (local_msu1_data)
1609 UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version);
1610
1611 if (version < SNAPSHOT_VERSION_IRQ)
1612 {
1613 printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION);
1614
1615 CPU.NMIPending = (CPU.Flags & (1 << 7)) ? TRUE : FALSE;
1616 CPU.IRQLine = (CPU.Flags & (1 << 11)) ? TRUE : FALSE;
1617 CPU.IRQTransition = FALSE;
1618 CPU.IRQLastState = FALSE;
1619 CPU.IRQExternal = (Obsolete.CPU_IRQActive & ~(1 << 1)) ? TRUE : FALSE;
1620
1621 switch (CPU.WhichEvent)
1622 {
1623 case 12: case 1: CPU.WhichEvent = 1; break;
1624 case 2: case 3: CPU.WhichEvent = 2; break;
1625 case 4: case 5: CPU.WhichEvent = 3; break;
1626 case 6: case 7: CPU.WhichEvent = 4; break;
1627 case 8: case 9: CPU.WhichEvent = 5; break;
1628 case 10: case 11: CPU.WhichEvent = 6; break;
1629 }
1630
1631 if (local_sa1) // FIXME
1632 {
1633 SA1.Cycles = SA1.PrevCycles = 0;
1634 SA1.TimerIRQLastState = FALSE;
1635 SA1.HTimerIRQPos = Memory.FillRAM[0x2212] | (Memory.FillRAM[0x2213] << 8);
1636 SA1.VTimerIRQPos = Memory.FillRAM[0x2214] | (Memory.FillRAM[0x2215] << 8);
1637 SA1.HCounter = 0;
1638 SA1.VCounter = 0;
1639 SA1.PrevHCounter = 0;
1640 SA1.MemSpeed = ONE_CYCLE;
1641 SA1.MemSpeedx2 = ONE_CYCLE * 2;
1642 }
1643 }
1644
1645 CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
1646 ICPU.ShiftedPB = Registers.PB << 16;
1647 ICPU.ShiftedDB = Registers.DB << 16;
1648 S9xSetPCBase(Registers.PBPC);
1649 S9xUnpackStatus();
1650 if(version < SNAPSHOT_VERSION_IRQ_2018)
1651 S9xUpdateIRQPositions(false); // calculate the new trigger pos from saved PPU data
1652 S9xFixCycles();
1653
1654 for (int d = 0; d < 8; d++)
1655 DMA[d] = dma_snap.dma[d];
1656 // TODO: these should already be correct since they are stored in the snapshot
1657 CPU.InDMA = CPU.InHDMA = FALSE;
1658 CPU.InDMAorHDMA = CPU.InWRAMDMAorHDMA = FALSE;
1659 CPU.HDMARanInDMA = 0;
1660
1661 S9xFixColourBrightness();
1662 S9xBuildDirectColourMaps();
1663 IPPU.ColorsChanged = TRUE;
1664 IPPU.OBJChanged = TRUE;
1665 IPPU.RenderThisFrame = TRUE;
1666
1667 GFX.InterlaceFrame = Timings.InterlaceField;
1668 GFX.DoInterlace = 0;
1669
1670 S9xGraphicsScreenResize();
1671
1672 if (Settings.FastSavestates == 0)
1673 memset(GFX.Screen,0,GFX.Pitch * MAX_SNES_HEIGHT);
1674
1675 // TODO: this seems to be a relic from 1.43 changes, completely remove if no issues in the future
1676 /*uint8 hdma_byte = Memory.FillRAM[0x420c];
1677 S9xSetCPU(hdma_byte, 0x420c);*/
1678
1679 S9xControlPostLoadState(&ctl_snap);
1680
1681 if (local_superfx)
1682 {
1683 GSU.pfPlot = fx_PlotTable[GSU.vMode];
1684 GSU.pfRpix = fx_PlotTable[GSU.vMode + 5];
1685 }
1686
1687 if (local_sa1 && local_sa1_registers)
1688 {
1689 SA1.Flags |= sa1_old_flags & TRACE_FLAG;
1690 S9xSA1PostLoadState();
1691 }
1692
1693 if (Settings.SDD1)
1694 S9xSDD1PostLoadState();
1695
1696 if (local_spc7110)
1697 S9xSPC7110PostLoadState(version);
1698
1699 if (local_srtc)
1700 S9xSRTCPostLoadState(version);
1701
1702 if (local_bsx_data)
1703 S9xBSXPostLoadState();
1704
1705 if (local_msu1_data)
1706 S9xMSU1PostLoadState();
1707
1708 if (local_movie_data)
1709 {
1710 // restore last displayed pad_read status
1711 extern bool8 pad_read, pad_read_last;
1712 bool8 pad_read_temp = pad_read;
1713
1714 pad_read = pad_read_last;
1715 S9xUpdateFrameCounter(-1);
1716 pad_read = pad_read_temp;
1717 }
1718
1719 if (local_screenshot)
1720 {
1721 SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo;
1722
1723 UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version);
1724
1725 IPPU.RenderedScreenWidth = min(ssi->Width, IMAGE_WIDTH);
1726 IPPU.RenderedScreenHeight = min(ssi->Height, IMAGE_HEIGHT);
1727 const bool8 scaleDownX = IPPU.RenderedScreenWidth < ssi->Width;
1728 const bool8 scaleDownY = IPPU.RenderedScreenHeight < ssi->Height && ssi->Height > SNES_HEIGHT_EXTENDED;
1729 GFX.DoInterlace = Settings.SupportHiRes ? ssi->Interlaced : 0;
1730
1731 uint8 *rowpix = ssi->Data;
1732 uint16 *screen = GFX.Screen;
1733
1734 for (int y = 0; y < IPPU.RenderedScreenHeight; y++, screen += GFX.RealPPL)
1735 {
1736 for (int x = 0; x < IPPU.RenderedScreenWidth; x++)
1737 {
1738 uint32 r, g, b;
1739
1740 r = *(rowpix++);
1741 g = *(rowpix++);
1742 b = *(rowpix++);
1743
1744 if (scaleDownX)
1745 {
1746 r = (r + *(rowpix++)) >> 1;
1747 g = (g + *(rowpix++)) >> 1;
1748 b = (b + *(rowpix++)) >> 1;
1749
1750 if (x + x + 1 >= ssi->Width)
1751 break;
1752 }
1753
1754 screen[x] = BUILD_PIXEL(r, g, b);
1755 }
1756
1757 if (scaleDownY)
1758 {
1759 rowpix += 3 * ssi->Width;
1760 if (y + y + 1 >= ssi->Height)
1761 break;
1762 }
1763 }
1764
1765 // black out what we might have missed
1766 for (uint32 y = IPPU.RenderedScreenHeight; y < (uint32) (IMAGE_HEIGHT); y++)
1767 memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);
1768
1769 delete ssi;
1770 }
1771 }
1772
1773 if (local_cpu) delete [] local_cpu;
1774 if (local_registers) delete [] local_registers;
1775 if (local_ppu) delete [] local_ppu;
1776 if (local_dma) delete [] local_dma;
1777 if (local_vram) delete [] local_vram;
1778 if (local_ram) delete [] local_ram;
1779 if (local_sram) delete [] local_sram;
1780 if (local_fillram) delete [] local_fillram;
1781 if (local_apu_sound) delete [] local_apu_sound;
1782 if (local_control_data) delete [] local_control_data;
1783 if (local_timing_data) delete [] local_timing_data;
1784 if (local_superfx) delete [] local_superfx;
1785 if (local_sa1) delete [] local_sa1;
1786 if (local_sa1_registers) delete [] local_sa1_registers;
1787 if (local_dsp1) delete [] local_dsp1;
1788 if (local_dsp2) delete [] local_dsp2;
1789 if (local_dsp4) delete [] local_dsp4;
1790 if (local_cx4_data) delete [] local_cx4_data;
1791 if (local_st010) delete [] local_st010;
1792 if (local_obc1) delete [] local_obc1;
1793 if (local_obc1_data) delete [] local_obc1_data;
1794 if (local_spc7110) delete [] local_spc7110;
1795 if (local_srtc) delete [] local_srtc;
1796 if (local_rtc_data) delete [] local_rtc_data;
1797 if (local_bsx_data) delete [] local_bsx_data;
1798 if (local_screenshot) delete [] local_screenshot;
1799 if (local_movie_data) delete [] local_movie_data;
1800
1801 return (result);
1802}
1803
1804static int FreezeSize (int size, int type)
1805{
1806 switch (type)
1807 {
1808 case uint32_ARRAY_V:
1809 case uint32_INDIR_ARRAY_V:
1810 return (size * 4);
1811
1812 case uint16_ARRAY_V:
1813 case uint16_INDIR_ARRAY_V:
1814 return (size * 2);
1815
1816 default:
1817 return (size);
1818 }
1819}
1820
1821static void FreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields, int num_fields)
1822{
1823 int len = 0;
1824 int i, j;
1825
1826 for (i = 0; i < num_fields; i++)
1827 {
1828 if (SNAPSHOT_VERSION < fields[i].debuted_in)
1829 {
1830 fprintf(stderr, "%s[%p]: field has bad debuted_in value %d, > %d.", name, (void *) fields, fields[i].debuted_in, SNAPSHOT_VERSION);
1831 continue;
1832 }
1833
1834 if (SNAPSHOT_VERSION < fields[i].deleted_in)
1835 len += FreezeSize(fields[i].size, fields[i].type);
1836 }
1837
1838 uint8 *block = new uint8[len];
1839 uint8 *ptr = block;
1840 uint8 *addr;
1841 uint16 word;
1842 uint32 dword;
1843 int64 qaword;
1844 int relativeAddr;
1845
1846 for (i = 0; i < num_fields; i++)
1847 {
1848 if (SNAPSHOT_VERSION >= fields[i].deleted_in || SNAPSHOT_VERSION < fields[i].debuted_in)
1849 continue;
1850
1851 addr = (uint8 *) base + fields[i].offset;
1852
1853 // determine real address of indirect-type fields
1854 // (where the structure contains a pointer to an array rather than the array itself)
1855 if (fields[i].type == uint8_INDIR_ARRAY_V || fields[i].type == uint16_INDIR_ARRAY_V || fields[i].type == uint32_INDIR_ARRAY_V)
1856 addr = (uint8 *) (*((pint *) addr));
1857
1858 // convert pointer-type saves from absolute to relative pointers
1859 if (fields[i].type == POINTER_V)
1860 {
1861 uint8 *pointer = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset));
1862 uint8 *relativeTo = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset2));
1863 relativeAddr = pointer - relativeTo;
1864 addr = (uint8 *) &relativeAddr;
1865 }
1866
1867 switch (fields[i].type)
1868 {
1869 case INT_V:
1870 case POINTER_V:
1871 switch (fields[i].size)
1872 {
1873 case 1:
1874 *ptr++ = *(addr);
1875 break;
1876
1877 case 2:
1878 word = *((uint16 *) (addr));
1879 *ptr++ = (uint8) (word >> 8);
1880 *ptr++ = (uint8) word;
1881 break;
1882
1883 case 4:
1884 dword = *((uint32 *) (addr));
1885 *ptr++ = (uint8) (dword >> 24);
1886 *ptr++ = (uint8) (dword >> 16);
1887 *ptr++ = (uint8) (dword >> 8);
1888 *ptr++ = (uint8) dword;
1889 break;
1890
1891 case 8:
1892 qaword = *((int64 *) (addr));
1893 *ptr++ = (uint8) (qaword >> 56);
1894 *ptr++ = (uint8) (qaword >> 48);
1895 *ptr++ = (uint8) (qaword >> 40);
1896 *ptr++ = (uint8) (qaword >> 32);
1897 *ptr++ = (uint8) (qaword >> 24);
1898 *ptr++ = (uint8) (qaword >> 16);
1899 *ptr++ = (uint8) (qaword >> 8);
1900 *ptr++ = (uint8) qaword;
1901 break;
1902 }
1903
1904 break;
1905
1906 case uint8_ARRAY_V:
1907 case uint8_INDIR_ARRAY_V:
1908 memmove(ptr, addr, fields[i].size);
1909 ptr += fields[i].size;
1910
1911 break;
1912
1913 case uint16_ARRAY_V:
1914 case uint16_INDIR_ARRAY_V:
1915 for (j = 0; j < fields[i].size; j++)
1916 {
1917 word = *((uint16 *) (addr + j * 2));
1918 *ptr++ = (uint8) (word >> 8);
1919 *ptr++ = (uint8) word;
1920 }
1921
1922 break;
1923
1924 case uint32_ARRAY_V:
1925 case uint32_INDIR_ARRAY_V:
1926 for (j = 0; j < fields[i].size; j++)
1927 {
1928 dword = *((uint32 *) (addr + j * 4));
1929 *ptr++ = (uint8) (dword >> 24);
1930 *ptr++ = (uint8) (dword >> 16);
1931 *ptr++ = (uint8) (dword >> 8);
1932 *ptr++ = (uint8) dword;
1933 }
1934
1935 break;
1936 }
1937 }
1938
1939 FreezeBlock(stream, name, block, len);
1940 delete [] block;
1941}
1942
1943static void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size)
1944{
1945 char buffer[20];
1946
1947 // check if it fits in 6 digits. (letting it go over and using strlen isn't safe)
1948 if (size <= 999999)
1949 sprintf(buffer, "%s:%06d:", name, size);
1950 else
1951 {
1952 // to make it fit, pack it in the bytes instead of as digits
1953 sprintf(buffer, "%s:------:", name);
1954 buffer[6] = (unsigned char) ((unsigned) size >> 24);
1955 buffer[7] = (unsigned char) ((unsigned) size >> 16);
1956 buffer[8] = (unsigned char) ((unsigned) size >> 8);
1957 buffer[9] = (unsigned char) ((unsigned) size >> 0);
1958 }
1959
1960 buffer[11] = 0;
1961
1962 WRITE_STREAM(buffer, 11, stream);
1963 WRITE_STREAM(block, size, stream);
1964}
1965
1966static bool CheckBlockName(STREAM stream, const char *name, int &len)
1967{
1968 char buffer[16];
1969 len = 0;
1970
1971 size_t l = READ_STREAM(buffer, 11, stream);
1972 buffer[l] = 0;
1973 REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0);
1974
1975 if (buffer[4] == '-')
1976 {
1977 len = (((unsigned char)buffer[6]) << 24)
1978 | (((unsigned char)buffer[7]) << 16)
1979 | (((unsigned char)buffer[8]) << 8)
1980 | (((unsigned char)buffer[9]) << 0);
1981 }
1982 else
1983 len = atoi(buffer + 4);
1984
1985 if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':')
1986 {
1987 return false;
1988 }
1989
1990 if (len <= 0)
1991 {
1992 return false;
1993 }
1994
1995 return true;
1996}
1997
1998static void SkipBlockWithName(STREAM stream, const char *name)
1999{
2000 int len;
2001 bool matchesName = CheckBlockName(stream, name, len);
2002 if (matchesName)
2003 {
2004 long rewind = FIND_STREAM(stream);
2005 rewind += len + 11;
2006 REVERT_STREAM(stream, rewind, 0);
2007 }
2008}
2009
2010static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size)
2011{
2012 char buffer[20];
2013 int len = 0, rem = 0;
2014 long rewind = FIND_STREAM(stream);
2015
2016 size_t l = READ_STREAM(buffer, 11, stream);
2017 buffer[l] = 0;
2018
2019 if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':')
2020 {
2021 err:
2022#ifdef DEBUGGER
2023 fprintf(stdout, "absent: %s(%d); next: '%.11s'\n", name, size, buffer);
2024#endif
2025 REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0);
2026 return (WRONG_FORMAT);
2027 }
2028
2029 if (buffer[4] == '-')
2030 {
2031 len = (((unsigned char) buffer[6]) << 24)
2032 | (((unsigned char) buffer[7]) << 16)
2033 | (((unsigned char) buffer[8]) << 8)
2034 | (((unsigned char) buffer[9]) << 0);
2035 }
2036 else
2037 len = atoi(buffer + 4);
2038
2039 if (len <= 0)
2040 goto err;
2041
2042 if (len > size)
2043 {
2044 rem = len - size;
2045 len = size;
2046 }
2047
2048 if (!Settings.FastSavestates)
2049 {
2050 memset(block, 0, size);
2051 }
2052
2053 if (READ_STREAM(block, len, stream) != (unsigned int) len)
2054 {
2055 REVERT_STREAM(stream, rewind, 0);
2056 return (WRONG_FORMAT);
2057 }
2058
2059 if (rem)
2060 {
2061 char *junk = new char[rem];
2062 len = READ_STREAM(junk, rem, stream);
2063 delete [] junk;
2064 if (len != rem)
2065 {
2066 REVERT_STREAM(stream, rewind, 0);
2067 return (WRONG_FORMAT);
2068 }
2069 }
2070
2071 return (SUCCESS);
2072}
2073
2074static int UnfreezeBlockCopy (STREAM stream, const char *name, uint8 **block, int size)
2075{
2076 int result;
2077
2078 //check name first to avoid memory allocation
2079 int blockLength;
2080 if (!CheckBlockName(stream, name, blockLength))
2081 {
2082 return 0;
2083 }
2084
2085 *block = new uint8[size];
2086
2087 result = UnfreezeBlock(stream, name, *block, size);
2088 if (result != SUCCESS)
2089 {
2090 delete [] (*block);
2091 *block = NULL;
2092 return (result);
2093 }
2094
2095 return (SUCCESS);
2096}
2097
2098static int UnfreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields, int num_fields, int version)
2099{
2100 int result;
2101 uint8 *block = NULL;
2102
2103 result = UnfreezeStructCopy(stream, name, &block, fields, num_fields, version);
2104 if (result != SUCCESS)
2105 {
2106 if (block != NULL)
2107 delete [] block;
2108 return (result);
2109 }
2110
2111 UnfreezeStructFromCopy(base, fields, num_fields, block, version);
2112 delete [] block;
2113
2114 return (SUCCESS);
2115}
2116
2117static int UnfreezeStructCopy (STREAM stream, const char *name, uint8 **block, FreezeData *fields, int num_fields, int version)
2118{
2119 int len = 0;
2120
2121 for (int i = 0; i < num_fields; i++)
2122 {
2123 if (version >= fields[i].debuted_in && version < fields[i].deleted_in)
2124 len += FreezeSize(fields[i].size, fields[i].type);
2125 }
2126
2127 return (UnfreezeBlockCopy(stream, name, block, len));
2128}
2129
2130static void UnfreezeStructFromCopy (void *sbase, FreezeData *fields, int num_fields, uint8 *block, int version)
2131{
2132 uint8 *ptr = block;
2133 uint16 word;
2134 uint32 dword;
2135 int64 qaword;
2136 uint8 *addr;
2137 void *base;
2138 int relativeAddr;
2139 int i, j;
2140
2141 for (i = 0; i < num_fields; i++)
2142 {
2143 if (version < fields[i].debuted_in || version >= fields[i].deleted_in)
2144 continue;
2145
2146 base = (SNAPSHOT_VERSION >= fields[i].deleted_in) ? ((void *) &Obsolete) : sbase;
2147 addr = (uint8 *) base + fields[i].offset;
2148
2149 if (fields[i].type == uint8_INDIR_ARRAY_V || fields[i].type == uint16_INDIR_ARRAY_V || fields[i].type == uint32_INDIR_ARRAY_V)
2150 addr = (uint8 *) (*((pint *) addr));
2151
2152 switch (fields[i].type)
2153 {
2154 case INT_V:
2155 case POINTER_V:
2156 switch (fields[i].size)
2157 {
2158 case 1:
2159 if (fields[i].offset < 0)
2160 {
2161 ptr++;
2162 break;
2163 }
2164
2165 *(addr) = *ptr++;
2166 break;
2167
2168 case 2:
2169 if (fields[i].offset < 0)
2170 {
2171 ptr += 2;
2172 break;
2173 }
2174
2175 word = *ptr++ << 8;
2176 word |= *ptr++;
2177 *((uint16 *) (addr)) = word;
2178 break;
2179
2180 case 4:
2181 if (fields[i].offset < 0)
2182 {
2183 ptr += 4;
2184 break;
2185 }
2186
2187 dword = *ptr++ << 24;
2188 dword |= *ptr++ << 16;
2189 dword |= *ptr++ << 8;
2190 dword |= *ptr++;
2191 *((uint32 *) (addr)) = dword;
2192 break;
2193
2194 case 8:
2195 if (fields[i].offset < 0)
2196 {
2197 ptr += 8;
2198 break;
2199 }
2200
2201 qaword = (int64) *ptr++ << 56;
2202 qaword |= (int64) *ptr++ << 48;
2203 qaword |= (int64) *ptr++ << 40;
2204 qaword |= (int64) *ptr++ << 32;
2205 qaword |= (int64) *ptr++ << 24;
2206 qaword |= (int64) *ptr++ << 16;
2207 qaword |= (int64) *ptr++ << 8;
2208 qaword |= (int64) *ptr++;
2209 *((int64 *) (addr)) = qaword;
2210 break;
2211
2212 default:
2213 assert(0);
2214 break;
2215 }
2216
2217 break;
2218
2219 case uint8_ARRAY_V:
2220 case uint8_INDIR_ARRAY_V:
2221 if (fields[i].offset >= 0)
2222 memmove(addr, ptr, fields[i].size);
2223 ptr += fields[i].size;
2224
2225 break;
2226
2227 case uint16_ARRAY_V:
2228 case uint16_INDIR_ARRAY_V:
2229 if (fields[i].offset < 0)
2230 {
2231 ptr += fields[i].size * 2;
2232 break;
2233 }
2234
2235 for (j = 0; j < fields[i].size; j++)
2236 {
2237 word = *ptr++ << 8;
2238 word |= *ptr++;
2239 *((uint16 *) (addr + j * 2)) = word;
2240 }
2241
2242 break;
2243
2244 case uint32_ARRAY_V:
2245 case uint32_INDIR_ARRAY_V:
2246 if (fields[i].offset < 0)
2247 {
2248 ptr += fields[i].size * 4;
2249 break;
2250 }
2251
2252 for (j = 0; j < fields[i].size; j++)
2253 {
2254 dword = *ptr++ << 24;
2255 dword |= *ptr++ << 16;
2256 dword |= *ptr++ << 8;
2257 dword |= *ptr++;
2258 *((uint32 *) (addr + j * 4)) = dword;
2259 }
2260
2261 break;
2262 }
2263
2264 if (fields[i].type == POINTER_V)
2265 {
2266 relativeAddr = (int) *((pint *) ((uint8 *) base + fields[i].offset));
2267 uint8 *relativeTo = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset2));
2268 *((pint *) (addr)) = (pint) (relativeTo + relativeAddr);
2269 }
2270 }
2271}
2272