|
|
1.1 root 1: /*
1.1.1.4 root 2: Hatari - memorySnapShot.c
3:
1.1.1.19 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: Memory Snapshot
8:
1.1.1.5 root 9: This handles the saving/restoring of the emulator's state so any game or
10: application can be saved and restored at any time. This is quite complicated
11: as we need to store all STRam, all chip states, all emulation variables and
12: then things get really complicated as we need to restore file handles
1.1 root 13: and such like.
1.1.1.5 root 14: To help keep things simple each file has one function which is used to
15: save/restore all variables that are local to it. We use one function to
16: reduce redundancy and the function 'MemorySnapShot_Store' decides if it
17: should save or restore the data.
1.1 root 18: */
1.1.1.13 root 19: const char MemorySnapShot_fileid[] = "Hatari memorySnapShot.c : " __DATE__ " " __TIME__;
1.1.1.10 root 20:
1.1.1.4 root 21: #include <SDL_types.h>
1.1.1.5 root 22: #include <errno.h>
1.1 root 23:
24: #include "main.h"
1.1.1.5 root 25: #include "blitter.h"
1.1.1.8 root 26: #include "configuration.h"
1.1.1.14 root 27: #include "debugui.h"
1.1.1.8 root 28: #include "dmaSnd.h"
1.1 root 29: #include "fdc.h"
30: #include "file.h"
31: #include "floppy.h"
1.1.1.20 root 32: #include "floppy_ipf.h"
33: #include "floppy_stx.h"
1.1 root 34: #include "gemdos.h"
1.1.1.19 root 35: #include "acia.h"
1.1 root 36: #include "ikbd.h"
1.1.1.15 root 37: #include "cycInt.h"
38: #include "cycles.h"
1.1.1.10 root 39: #include "ioMem.h"
1.1.1.7 root 40: #include "log.h"
1.1 root 41: #include "m68000.h"
42: #include "memorySnapShot.h"
43: #include "mfp.h"
1.1.1.21 root 44: #include "midi.h"
1.1 root 45: #include "psg.h"
46: #include "reset.h"
47: #include "sound.h"
1.1.1.14 root 48: #include "str.h"
1.1.1.15 root 49: #include "stMemory.h"
1.1 root 50: #include "tos.h"
1.1.1.16 root 51: #include "screen.h"
1.1.1.22! root 52: #include "screenConvert.h"
1.1 root 53: #include "video.h"
1.1.1.14 root 54: #include "falcon/dsp.h"
1.1.1.16 root 55: #include "falcon/crossbar.h"
56: #include "falcon/videl.h"
57: #include "statusbar.h"
1.1.1.21 root 58: #include "cart.h"
1.1.1.2 root 59:
1.1 root 60:
1.1.1.22! root 61: #define VERSION_STRING "2.0.0" /* Version number of compatible memory snapshots - Always 6 bytes (inc' NULL) */
1.1.1.21 root 62: #define SNAPSHOT_MAGIC 0xDeadBeef
1.1.1.6 root 63:
1.1.1.20 root 64: #if HAVE_LIBZ
1.1.1.8 root 65: #define COMPRESS_MEMORYSNAPSHOT /* Compress snapshots to reduce disk space used */
1.1.1.20 root 66: #endif
1.1 root 67:
1.1.1.5 root 68: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1 root 69:
1.1.1.16 root 70: /* Remove possible conflicting mkdir declaration from cpu/sysdeps.h */
71: #undef mkdir
1.1.1.5 root 72: #include <zlib.h>
73: typedef gzFile MSS_File;
74:
75: #else
76:
77: typedef FILE* MSS_File;
1.1 root 78:
1.1.1.5 root 79: #endif
80:
81:
82: static MSS_File CaptureFile;
1.1.1.12 root 83: static bool bCaptureSave, bCaptureError;
1.1.1.5 root 84:
85:
86: /*-----------------------------------------------------------------------*/
1.1.1.10 root 87: /**
88: * Open file.
89: */
1.1.1.7 root 90: static MSS_File MemorySnapShot_fopen(const char *pszFileName, const char *pszMode)
1.1 root 91: {
92: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 93: return gzopen(pszFileName, pszMode);
94: #else
95: return fopen(pszFileName, pszMode);
96: #endif
1.1 root 97: }
98:
1.1.1.5 root 99:
100: /*-----------------------------------------------------------------------*/
1.1.1.10 root 101: /**
102: * Close file.
103: */
1.1.1.5 root 104: static void MemorySnapShot_fclose(MSS_File fhndl)
1.1 root 105: {
106: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 107: gzclose(fhndl);
108: #else
109: fclose(fhndl);
110: #endif
1.1 root 111: }
112:
1.1.1.5 root 113:
114: /*-----------------------------------------------------------------------*/
1.1.1.10 root 115: /**
116: * Read from file.
117: */
1.1.1.5 root 118: static int MemorySnapShot_fread(MSS_File fhndl, char *buf, int len)
1.1 root 119: {
120: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5 root 121: return gzread(fhndl, buf, len);
122: #else
123: return fread(buf, 1, len, fhndl);
124: #endif
1.1 root 125: }
126:
1.1.1.5 root 127:
128: /*-----------------------------------------------------------------------*/
1.1.1.10 root 129: /**
130: * Write data to file.
131: */
1.1.1.7 root 132: static int MemorySnapShot_fwrite(MSS_File fhndl, const char *buf, int len)
1.1 root 133: {
1.1.1.5 root 134: #ifdef COMPRESS_MEMORYSNAPSHOT
135: return gzwrite(fhndl, buf, len);
136: #else
137: return fwrite(buf, 1, len, fhndl);
138: #endif
1.1 root 139: }
140:
1.1.1.5 root 141:
142: /*-----------------------------------------------------------------------*/
1.1.1.10 root 143: /**
1.1.1.20 root 144: * Seek into file from current position
145: */
146: static int MemorySnapShot_fseek(MSS_File fhndl, int pos)
147: {
148: #ifdef COMPRESS_MEMORYSNAPSHOT
149: return (int)gzseek(fhndl, pos, SEEK_CUR); /* return -1 if error, new position >=0 if OK */
150: #else
1.1.1.21 root 151: return fseek(fhndl, pos, SEEK_CUR); /* return -1 if error, 0 if OK */
1.1.1.20 root 152: #endif
153: }
154:
155:
156: /*-----------------------------------------------------------------------*/
157: /**
1.1.1.10 root 158: * Open/Create snapshot file, and set flag so 'MemorySnapShot_Store' knows
159: * how to handle data.
160: */
1.1.1.22! root 161: static bool MemorySnapShot_OpenFile(const char *pszFileName, bool bSave, bool bConfirm)
1.1 root 162: {
1.1.1.16 root 163: char VersionString[] = VERSION_STRING;
1.1.1.21 root 164: #if ENABLE_WINUAE_CPU
165: # define CORE_VERSION 1
166: #else
167: # define CORE_VERSION 0
168: #endif
169: Uint8 CpuCore;
1.1.1.3 root 170:
1.1.1.5 root 171: /* Set error */
1.1.1.14 root 172: bCaptureError = false;
1.1 root 173:
1.1.1.16 root 174: /* after opening file, set bCaptureSave to indicate whether
175: * 'MemorySnapShot_Store' should load from or save to a file
176: */
1.1.1.5 root 177: if (bSave)
178: {
1.1.1.22! root 179: if (bConfirm && !File_QueryOverwrite(pszFileName))
! 180: {
! 181: /* info for debugger invocation */
! 182: Log_Printf(LOG_INFO, "Save canceled.");
1.1.1.16 root 183: return false;
1.1.1.22! root 184: }
1.1.1.5 root 185: /* Save */
186: CaptureFile = MemorySnapShot_fopen(pszFileName, "wb");
187: if (!CaptureFile)
188: {
1.1.1.22! root 189: Log_Printf(LOG_WARN, "Save file open error: %s",strerror(errno));
1.1.1.14 root 190: bCaptureError = true;
191: return false;
1.1.1.5 root 192: }
1.1.1.14 root 193: bCaptureSave = true;
1.1.1.5 root 194: /* Store version string */
1.1.1.16 root 195: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.21 root 196: /* Store CPU core version */
197: CpuCore = CORE_VERSION;
198: MemorySnapShot_Store(&CpuCore, sizeof(CpuCore));
1.1.1.5 root 199: }
200: else
201: {
202: /* Restore */
203: CaptureFile = MemorySnapShot_fopen(pszFileName, "rb");
204: if (!CaptureFile)
205: {
1.1.1.22! root 206: Log_Printf(LOG_WARN, "File open error: %s", strerror(errno));
1.1.1.14 root 207: bCaptureError = true;
208: return false;
1.1.1.5 root 209: }
1.1.1.14 root 210: bCaptureSave = false;
1.1.1.5 root 211: /* Restore version string */
1.1.1.16 root 212: MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5 root 213: /* Does match current version? */
1.1.1.21 root 214: if (strcmp(VersionString, VERSION_STRING))
1.1.1.5 root 215: {
216: /* No, inform user and error */
1.1.1.21 root 217: Log_AlertDlg(LOG_ERROR,
218: "Unable to restore Hatari memory state.\n"
219: "Given state file is compatible only with\n"
220: "Hatari version " VERSION_STRING ".");
221: bCaptureError = true;
222: return false;
223: }
224: /* Check CPU core version */
225: MemorySnapShot_Store(&CpuCore, sizeof(CpuCore));
226: if (CpuCore != CORE_VERSION)
227: {
228: Log_AlertDlg(LOG_ERROR,
229: "Unable to restore Hatari memory state.\n"
230: "Given state file is for different Hatari\n"
231: "CPU core version.");
1.1.1.14 root 232: bCaptureError = true;
233: return false;
1.1.1.5 root 234: }
235: }
1.1 root 236:
1.1.1.5 root 237: /* All OK */
1.1.1.14 root 238: return true;
1.1 root 239: }
240:
1.1.1.5 root 241:
242: /*-----------------------------------------------------------------------*/
1.1.1.10 root 243: /**
244: * Close snapshot file.
245: */
1.1.1.5 root 246: static void MemorySnapShot_CloseFile(void)
1.1 root 247: {
1.1.1.5 root 248: MemorySnapShot_fclose(CaptureFile);
1.1 root 249: }
250:
1.1.1.5 root 251:
252: /*-----------------------------------------------------------------------*/
1.1.1.10 root 253: /**
1.1.1.20 root 254: * Skip Nb bytes when reading from/writing to file.
255: */
256: void MemorySnapShot_Skip(int Nb)
257: {
258: int res;
259:
260: /* Check no file errors */
261: if (CaptureFile != NULL)
262: {
263: res = MemorySnapShot_fseek(CaptureFile, Nb);
264:
265: /* Did seek OK? */
266: if (res < 0)
267: bCaptureError = true;
268: }
269: }
270:
271:
272: /*-----------------------------------------------------------------------*/
273: /**
1.1.1.10 root 274: * Save/Restore data to/from file.
275: */
1.1 root 276: void MemorySnapShot_Store(void *pData, int Size)
277: {
1.1.1.5 root 278: long nBytes;
1.1.1.3 root 279:
1.1.1.5 root 280: /* Check no file errors */
281: if (CaptureFile != NULL)
282: {
283: /* Saving or Restoring? */
284: if (bCaptureSave)
285: nBytes = MemorySnapShot_fwrite(CaptureFile, (char *)pData, Size);
286: else
287: nBytes = MemorySnapShot_fread(CaptureFile, (char *)pData, Size);
288:
289: /* Did save OK? */
290: if (nBytes != Size)
1.1.1.14 root 291: bCaptureError = true;
1.1.1.5 root 292: }
1.1 root 293: }
294:
1.1.1.5 root 295:
296: /*-----------------------------------------------------------------------*/
1.1.1.10 root 297: /**
298: * Save 'snapshot' of memory/chips/emulation variables
299: */
1.1.1.12 root 300: void MemorySnapShot_Capture(const char *pszFileName, bool bConfirm)
1.1 root 301: {
1.1.1.21 root 302: Uint32 magic = SNAPSHOT_MAGIC;
303:
1.1.1.5 root 304: /* Set to 'saving' */
1.1.1.22! root 305: if (MemorySnapShot_OpenFile(pszFileName, true, bConfirm))
1.1.1.5 root 306: {
307: /* Capture each files details */
1.1.1.14 root 308: Configuration_MemorySnapShot_Capture(true);
309: TOS_MemorySnapShot_Capture(true);
1.1.1.15 root 310: STMemory_MemorySnapShot_Capture(true);
1.1.1.20 root 311: Cycles_MemorySnapShot_Capture(true); /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14 root 312: FDC_MemorySnapShot_Capture(true);
313: Floppy_MemorySnapShot_Capture(true);
1.1.1.20 root 314: IPF_MemorySnapShot_Capture(true); /* After fdc/floppy are saved */
315: STX_MemorySnapShot_Capture(true); /* After fdc/floppy are saved */
1.1.1.14 root 316: GemDOS_MemorySnapShot_Capture(true);
1.1.1.19 root 317: ACIA_MemorySnapShot_Capture(true);
1.1.1.14 root 318: IKBD_MemorySnapShot_Capture(true);
1.1.1.21 root 319: MIDI_MemorySnapShot_Capture(true);
1.1.1.15 root 320: CycInt_MemorySnapShot_Capture(true);
1.1.1.14 root 321: M68000_MemorySnapShot_Capture(true);
322: MFP_MemorySnapShot_Capture(true);
323: PSG_MemorySnapShot_Capture(true);
324: Sound_MemorySnapShot_Capture(true);
325: Video_MemorySnapShot_Capture(true);
326: Blitter_MemorySnapShot_Capture(true);
327: DmaSnd_MemorySnapShot_Capture(true);
1.1.1.16 root 328: Crossbar_MemorySnapShot_Capture(true);
329: VIDEL_MemorySnapShot_Capture(true);
1.1.1.14 root 330: DSP_MemorySnapShot_Capture(true);
1.1.1.15 root 331: DebugUI_MemorySnapShot_Capture(pszFileName, true);
1.1.1.16 root 332: IoMem_MemorySnapShot_Capture(true);
1.1.1.22! root 333: ScreenConv_MemorySnapShot_Capture(true);
! 334:
1.1.1.21 root 335: /* end marker */
336: MemorySnapShot_Store(&magic, sizeof(magic));
1.1.1.5 root 337: /* And close */
338: MemorySnapShot_CloseFile();
1.1.1.16 root 339: } else {
340: /* just canceled? */
341: if (!bCaptureError)
342: return;
1.1.1.5 root 343: }
344:
345: /* Did error */
346: if (bCaptureError)
1.1.1.22! root 347: Log_AlertDlg(LOG_ERROR, "Unable to save memory state to file: %s", pszFileName);
1.1.1.10 root 348: else if (bConfirm)
1.1.1.22! root 349: Log_AlertDlg(LOG_INFO, "Memory state file saved: %s", pszFileName);
! 350: else
! 351: Log_Printf(LOG_INFO, "Memory state file saved: %s", pszFileName);
1.1 root 352: }
353:
1.1.1.5 root 354:
355: /*-----------------------------------------------------------------------*/
1.1.1.10 root 356: /**
357: * Restore 'snapshot' of memory/chips/emulation variables
358: */
1.1.1.12 root 359: void MemorySnapShot_Restore(const char *pszFileName, bool bConfirm)
1.1 root 360: {
1.1.1.21 root 361: Uint32 magic;
362:
1.1.1.5 root 363: /* Set to 'restore' */
1.1.1.22! root 364: if (MemorySnapShot_OpenFile(pszFileName, false, bConfirm))
1.1.1.5 root 365: {
1.1.1.14 root 366: Configuration_MemorySnapShot_Capture(false);
367: TOS_MemorySnapShot_Capture(false);
1.1.1.10 root 368:
1.1.1.5 root 369: /* Reset emulator to get things running */
1.1.1.10 root 370: IoMem_UnInit(); IoMem_Init();
1.1.1.5 root 371: Reset_Cold();
372:
373: /* Capture each files details */
1.1.1.15 root 374: STMemory_MemorySnapShot_Capture(false);
1.1.1.20 root 375: Cycles_MemorySnapShot_Capture(false); /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14 root 376: FDC_MemorySnapShot_Capture(false);
377: Floppy_MemorySnapShot_Capture(false);
1.1.1.20 root 378: IPF_MemorySnapShot_Capture(false); /* After fdc/floppy are restored, as IPF depends on them */
379: STX_MemorySnapShot_Capture(false); /* After fdc/floppy are restored, as STX depends on them */
1.1.1.14 root 380: GemDOS_MemorySnapShot_Capture(false);
1.1.1.19 root 381: ACIA_MemorySnapShot_Capture(false);
382: IKBD_MemorySnapShot_Capture(false); /* After ACIA */
1.1.1.21 root 383: MIDI_MemorySnapShot_Capture(false);
1.1.1.15 root 384: CycInt_MemorySnapShot_Capture(false);
1.1.1.14 root 385: M68000_MemorySnapShot_Capture(false);
386: MFP_MemorySnapShot_Capture(false);
387: PSG_MemorySnapShot_Capture(false);
388: Sound_MemorySnapShot_Capture(false);
389: Video_MemorySnapShot_Capture(false);
390: Blitter_MemorySnapShot_Capture(false);
391: DmaSnd_MemorySnapShot_Capture(false);
1.1.1.16 root 392: Crossbar_MemorySnapShot_Capture(false);
393: VIDEL_MemorySnapShot_Capture(false);
1.1.1.14 root 394: DSP_MemorySnapShot_Capture(false);
1.1.1.15 root 395: DebugUI_MemorySnapShot_Capture(pszFileName, false);
1.1.1.16 root 396: IoMem_MemorySnapShot_Capture(false);
1.1.1.22! root 397: ScreenConv_MemorySnapShot_Capture(false);
1.1.1.5 root 398:
1.1.1.21 root 399: /* version string check catches release-to-release
400: * state changes, bCaptureError catches too short
401: * state file, this check a too long state file.
402: */
403: MemorySnapShot_Store(&magic, sizeof(magic));
404: if (!bCaptureError && magic != SNAPSHOT_MAGIC)
405: bCaptureError = true;
406:
1.1.1.5 root 407: /* And close */
408: MemorySnapShot_CloseFile();
1.1.1.16 root 409:
1.1.1.21 root 410: /* Apply patches for gemdos HD if needed */
411: /* (we need to do it after cpu tables for all opcodes were rebuilt) */
412: Cart_Patch();
413:
1.1.1.16 root 414: /* changes may affect also info shown in statusbar */
415: Statusbar_UpdateInfo();
1.1.1.21 root 416:
417: if (bCaptureError)
418: {
419: Log_AlertDlg(LOG_ERROR, "Full memory state restore failed!\nPlease reboot emulation.");
420: return;
421: }
1.1.1.5 root 422: }
423:
424: /* Did error? */
425: if (bCaptureError)
1.1.1.22! root 426: Log_AlertDlg(LOG_ERROR, "Unable to restore memory state from file: %s", pszFileName);
1.1.1.10 root 427: else if (bConfirm)
1.1.1.22! root 428: Log_AlertDlg(LOG_INFO, "Memory state file restored: %s", pszFileName);
! 429: else
! 430: Log_Printf(LOG_INFO, "Memory state file restored: %s", pszFileName);
1.1 root 431: }
1.1.1.10 root 432:
433:
434: /*-----------------------------------------------------------------------*/
435: /*
436: * Save and restore functions required by the UAE CPU core...
437: * ... don't use them in normal Hatari code!
438: */
439: #include <savestate.h>
440:
1.1.1.21 root 441: void save_u64(uae_u64 data)
442: {
443: MemorySnapShot_Store(&data, 8);
444: }
445:
1.1.1.10 root 446: void save_u32(uae_u32 data)
447: {
448: MemorySnapShot_Store(&data, 4);
1.1.1.21 root 449: //printf ("s32 %x\n", data);
1.1.1.10 root 450: }
451:
452: void save_u16(uae_u16 data)
453: {
454: MemorySnapShot_Store(&data, 2);
1.1.1.21 root 455: //printf ("s16 %x\n", data);
456: }
457:
458: void save_u8(uae_u8 data)
459: {
460: MemorySnapShot_Store(&data, 1);
461: //printf ("s8 %x\n", data);
462: }
463:
464: uae_u64 restore_u64(void)
465: {
466: uae_u64 data;
467: MemorySnapShot_Store(&data, 8);
468: return data;
1.1.1.10 root 469: }
470:
471: uae_u32 restore_u32(void)
472: {
473: uae_u32 data;
474: MemorySnapShot_Store(&data, 4);
1.1.1.21 root 475: //printf ("r32 %x\n", data);
1.1.1.10 root 476: return data;
477: }
478:
479: uae_u16 restore_u16(void)
480: {
481: uae_u16 data;
482: MemorySnapShot_Store(&data, 2);
1.1.1.21 root 483: //printf ("r16 %x\n", data);
1.1.1.10 root 484: return data;
485: }
1.1.1.21 root 486:
487: uae_u8 restore_u8(void)
488: {
489: uae_u8 data;
490: MemorySnapShot_Store(&data, 1);
491: //printf ("r8 %x\n", data);
492: return data;
493: }
494:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.