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